2011-07-01 12 views
5

지난 며칠 동안 한 스레드가 다른 스레드가 여전히 사용중인 개체를 삭제하는 멀티 스레딩을 디버깅 한 결과,이 문제를 '휘발성'으로 만들 수 있었 더라면 문제를 훨씬 쉽고 빨리 진단 할 수 있다는 것을 깨달았습니다. 시스템 (Symbian OS)의 크래시 덤프가 훨씬 유익한 것으로 바뀌었을 것입니다.왜 'this'가 변동성이 없습니까?

그렇다면 왜 그렇게 될 수 없거나 그렇게해서는 안되는 이유가 무엇입니까?

편집 : 따라서이 시나리오를 방지하거나 확인하는 안전한 방법은 없습니다. 부실 클래스 포인터에 액세스하는 한 가지 해결책은 포인터를 보유하는 전역 변수를 갖는 것이며, 호출되는 함수는 전역 변수를 'this'대신에 사용하는 정적이어야합니다.

static TAny* gGlobalPointer = NULL; 

#define Harness static_cast<CSomeClass*>(gGlobalPointer); 

class CSomeClass : public CBase 
    { 
public: 
    static void DoSomething(); 

private: 
    int iMember; 
    }; 


void CSomeClass::DoSomething() 
    { 
    if (!Harness) 
     { 
     return; 
     } 

    Harness->iMember = 0; 
    } 

따라서 다른 스레드가 전역 포인터를 삭제하고 NULL로 지정하면 즉시 캐치됩니다.

필자가 생각하기에 컴파일러가 Harness의 값을 캐시 할 때마다 매번 검사하는 것이 아니라고 생각합니다.

+0

'this'가 휘발성이거나 'this'가 휘발성 포인터 인 경우 더 쉬웠을 것입니까? 즉, 크래시 덤프에서 오래된 값인 'this'(변경되지 않으므로 조금 이상하게 보임) 또는 일부 데이터 멤버를 보았습니까? –

답변

7

변수하지만, 일정하지 않다. 이 참조하는 개체를이으로 변경할 수 있지만 값을 변경할 수 없습니다.. 상수는 절대로 바뀌지 않으므로 휘발성으로 표시 할 필요가 없습니다.

+1

그리고 "상수"에 의해 당신은'const * *'이 아닌'T * const'를 의미합니다. –

+2

대답은 실제로 C++ 용어로 이해가되지 않습니다. 'this'는 표현식입니다. 그리고'const' 표현식은 확실히 C++에서 바뀔 수 있습니다 :'int x = 0; int const * px = & x; std :: cout << * px; x = 1; std :: cout << * px;'. – MSalters

+0

@Mike no 그는 'T * const'를 의미하지 않는다. 그는 객체가 아닌'T *'를 의미한다. 'this'''''''''''' 역시 마찬가지입니다. 글쎄, 적어도 나는 그가 의미하는 것으로 생각하고있다. 그렇지 않으면 그의 대답은 나에게 이해가되지 않는다! –

2

될 수 있습니다. 멤버 함수를 volatile로 선언하면됩니다.

struct a 
{ 
    void foo() volatile {} 
}; 
+1

그리고 실제 질문에 답하기 위해 이것이 기본적으로 일어나지 않는 이유는 포인터를 비 휘발성으로 취하는 함수에'this '를 전달할 수 없다는 것입니다. 같은 이유로'this'는 멤버 함수'const'를 표시하지 않으면 const에 대한 포인터가 아닙니다. –

2

휘발성 도움이되지 않습니다.
변수에 대한 액세스가 휘발성이되지만 메서드 완료를 기다리지는 않습니다.

스마트 포인터를 사용하십시오.

shared_ptr

또한 새로운 C++ 버전에서 표준의 버전이있다.

+0

Symbian C++에서 스마트 포인터가 없습니다. 나는 그것이 동기화를 제공하기를 원하지 않았다. 나는 낡은 포인터에 접근 할 때 충돌을 원했다. – James

+0

@James : 불행하게도 이것을 휘발성으로 만들지는 못합니다. –

+0

공유 포인터는 템플릿이있는 클래스입니다 .. 당신은 그것을 dowonload하고 프로젝트에 추가 할 수 있습니다 –

4

변수가 휘발성이라는 것은 컴파일러가 액세스 할 때마다 메모리에서 값을 읽음을 의미하지만 this의 값은 다른 컨텍스트 또는 같은 경우, 가리키는 객체를 삭제합니다.

+2

...왜냐하면 포인터를 삭제하면 (특히 포인터가 가리키는 메모리) 마술처럼 포인터를 '0'으로 설정하지 않기 때문입니다. 컴파일러는 객체에 대한 모든 포인터가 어디에 있는지 알 수있는 방법이 없습니다. –

+0

여러 답을 수락 할 수 있다면 가능합니다. 감사 – James

0

삭제 중에 개체를 읽는 중 이는 명확한 메모리 오류이며 휘발성 데이터와 관련이 없습니다.

휘발성 (volatile)은 컴파일러가 다른 스레드에 의해 변경 될 수있는 메모리 변수를 "기억"하지 못하도록하기위한 것입니다. 즉, 컴파일러가 최적화되지 못하도록합니다.

클래스 포인터 멤버 페이지를 가지고 있으며, 여러분의 방법은 액세스하는 경우 :

p->a; 
p->b; 

등, p는이 p->a

를했을 때 그것을보다 "이"그래서 p->b 다른 개체에 액세스 할 수 내 휘발성 p가 삭제 된 경우 "이"가 삭제되었으므로 휘발성이 사용자의 구출에 부합하지 않습니다. 아마 당신은 그것이 "무효화"될 것이라고 생각하지만 그렇게되지는 않을 것입니다.

덧붙여 말하자면 소멸자가 동일한 객체를 사용하여 다른 스레드를 보호하기 위해 뮤텍스를 잠그는 경우 문제가 발생한다는 것은 꽤 좋은 규칙입니다. 소멸자는 동기 작업이 필요한 외부 객체에서 자신의 존재를 제거하지만 자체 구성원을 보호하지 않기 때문에 잠글 수 있습니다.

관련 문제