2011-08-20 4 views
4

구조체를 다른 스레드로 보내려면 창 메시지 대기열 기능을 사용하고 싶습니다. 하지만 postthreadmessage 함수는 인자를 전달하기 위해 두 개의 정수 매개 변수 인 lparam과 wparam만을 제공한다는 것을 알게되었습니다. 그래서 struct의 주소를 lparam에 넣기로했습니다. 이것은 Windows가 구조체를 전달하는 데 사용하는 올바른 방법입니까?postThreadMessage를 사용하여 구조체를 전달하는 방법

그리고 boost :: shared_ptr을 사용하여 구조체의 주소를 수신자 스레드와 송신기 스레드 모두에서 유지하려고합니다. 두 shared_ptrs가 범위를 벗어날 때 구조체가 두 번 해제 될 것입니까? 힙에 할당 된 구조체가 100 % 해제 될 수있는 방법을 알아낼 수 없습니다. 어떤 아이디어입니까?

+1

예, 물론입니다. WM_COPYDATA를 비교하십시오. 단순히 수신기가 메모리를 비우도록하십시오. 수신 스레드가 메시지 상자가 아닌 창을 표시하는 경우 PostThreadMessage()를 사용하지 마십시오. –

+0

@Hans Passant 오래된 게시물 알아,하지만이 경우 PostThreadMessage()를 사용하는 것이 나쁜 이유를 간략하게 설명 할 수 있습니까? 그 결과는 무엇일까요? –

답변

0

첫 번째 질문에 그렇습니다. 예, LPARAM은 정수 또는 포인터로 사용하기위한 것입니다. 그 정의에서 분명하다 :

typedef LONG_PTR LPARAM; 

이것은 포인터를 저장할만큼 충분히 긴 정수이다.

shared_ptr<Thing> a; 
PostThreadMessage(x, 0, (LPARAM)a.get()); 
... 
LRESULT OnMessage(int msg, WPARAM wp, LPARAM lp) 
{ 
    shared_ptr<Thing> p((Thing*)lp); //Bad!!! 
} 

하지만 대신이 해결 방법을 시도 할 수 있습니다 :

shared_ptr<Thing> a; 
PostThreadMessage(x, 0, new shared_ptr<Thing>(a)); //pointer to smart-pointer 
... 
LRESULT OnMessage(int msg, WPARAM wp, LPARAM lp) 
{ 
    shared_ptr<Thing> *pp = (shared_ptr<Thing>*)lp; 
    shared_ptr<Thing> p(*pp); 
    delete pp; //no leak 
} 
shared_ptr의 일에 대해

, 당신은 원시 포인터를 전달하고 다른 shared_ptr의로 묶지 경우 두 번 무료 것 맞다

AFTERTHOUGHT : PostThreadMessage가 실패 할 수 있습니다 ... 그리고 shared_ptr을 누설하고 싶지는 않습니다.

내 경험에 의하면 일반적으로 데이터를 보유하고 거기에 데이터가 있음을 알리기 위해 PostThreadMessage를 사용하기 위해 std :: deque를 사용하는 것이 더 좋습니다. 이런 식으로 당신은 결코 물건을 잃지 않을 것입니다! YMMV

+0

예. 공유 데이터를 직접 사용하려면 명시 적으로 스레드 동기화가 필요하고 차단됩니다. 메시지를 사용하는 이유는 비동기 쓰기가 필요하고 명시 적 잠금 작업이 필요하지 않기 때문입니다.필자는 작가 스레드에서 메모리를 할당하고 독자 스레드에서 자유롭게 사용할 수 있다고 생각합니다. PostThreadMessage가 결코 실패하지 않기를 바랍니다 ... – Jason

+0

afterthought에 대한 의견 : 'weak_ptr'에 대한 포인터 사용 방법은 어떻습니까? 'weak_ptr'을 누설하는 것은'shared_ptr'을 누출하는 것보다 훨씬 낫습니다. 그리고 메시지의 발신자가'shared_ptr a'에 걸려있는 한, 수령인이 그것을 필요로 할 때 객체는 여전히 존재할 것입니다. –

+1

PostThreadMessage는 두 가지 경우에만 실패합니다. a) 대상 큐가 꽉 찼습니다 (약 40000 개의 메시지를 계산했지만 한계는 문서화되지 않았으므로 여러 매개 변수에 따라 다를 수 있음). b) 타겟 쓰레드가 아직 메시지 큐를 생성하지 않았다. 대기열은 스레드가 처음 함수에 액세스 할 때 자동으로 생성됩니다 (예 :'GetMessage'). 그래서 쓰레드를 만들고'PostThreadMessage'를 호출 한 직후에 _might_ 실패합니다. 안전을 위해서 반환 값을 체크하면된다.'PostThreadMessage'는 실패하면'FALSE'를 리턴한다. – rodrigo

0

나는 void*를 사용하여 데이터를 보유하고있는 Qt는 QModelIndex 클래스를 사용하여 비슷한 상황 건너했지만, 나는 그것이 shared_ptr을 사용하여 가리키는 것 데이터를 관리 할 수 ​​있습니다.

을 직접 참조 해제하는 것을 피하기 위해 더 이상 존재하지 않는 객체를 가리킬 수도 있으므로 에서 weak_ptr까지의지도를 사용합니다. QModelIndexes이 참조하는 모든 개체는 맵에 저장됩니다. 을 참조 취소 할 때, void*을 키로 사용하여 해당 weak_ptr을지도에서 검색 한 다음 weak_ptrshared_ptr으로 변환합니다. shared_ptrvoid*과 같거나 NULL이므로 형식 안전성을 얻을 수 있습니다.

내 솔루션은 사용자가 언급 한 동시성 문제를 처리 할 필요가 없었지만 상황에 맞게 적용 할 수 있습니다. lparam을 사용하여 객체에 원시 포인터를 저장 한 다음지도를 사용하여 원시 포인터에서 스마트 포인터로 변환 할 수 있습니다. 뮤텍스로지도를 보호하면 거기에있을 수 있습니다.

관련 문제