2009-03-07 8 views
1

메시지 대기 루프가있는 스레드가 내 Delphi 응용 프로그램에 있습니다. 메시지를받을 때마다 작업을 시작합니다. 이 스레드의 실행 절차는 다음과 같습니다.스레드가 메시지를 수신하지 않습니다.

procedure TMyThread.Execute; 
begin 
    while GetMessage(Msg, 0, 0, 0) and not Terminated do 
    begin 
    {thread message} 
    if Msg.hwnd = 0 then 
    begin 
     ... 
    end 
    else 
     DispatchMessage(Msg); 
    end; 
end; 

응용 프로그램을 사용하여 일부 테스트 수행 GetMessage 함수가 주 스레드에 의존한다는 사실을 발견했습니다. 이것은 메인 스레드가 일부 작업을 수행하는 동안 메시지가 수신 대기 중일 때 (메시지가 PostThreadMessage 함수를 사용하는 또 다른 스레드에 의해 전송 된 경우에도 내 스레드의 GetMessage 함수가 반환되지 않음을 의미합니다. PostMessage MyThreadId, WM_MyMessage, 0, 0)).

주 스레드가 작업을 끝내거나 Application.ProcessMessages 메서드가 호출 될 때만 GetMessage가 반환되고 스레드가 작업을 시작합니다. 이런 종류의 스레드 간 통신을 구현하면 내 스레드가 독립적으로 작동하고 스레드에 직접 전송되는 메시지의 수신이 주 스레드에 종속된다는 것을 결코 기대하지 않을 것입니다.

테스트 수행 주 스레드에서 WaitForSingleObject 함수를 사용하여 몇 초 동안 이벤트를 기다렸습니다. 이것은 메시지가 다른 스레드에 의해 보내 졌음에도 불구하고 내 스레드가 어떤 작업도 수행하지 않고 있다는 것을 알았을 때입니다. WaitForSingleObject 함수가 마침내 대기를 끝내고 주 스레드가 유휴 상태가되면 스레드의 GetMessage 함수가 반환됩니다.

누군가가 왜 이런 방식으로 작동하는지 설명 할 수 있습니까? 거기에 해결 방법이 있습니까? 내 스레드가 독립적으로 메시지를 수신하도록하고 싶습니다. 모든 스레드는 메인 스레드에 의해 생성됩니다. 이것이 그 이유일까요?

미리 도움을 주셔서 감사합니다.

마리우스.


Mghie, 당신은 절대적으로 다시 오른쪽 (당신은, 당신이 기억 수도 최근 메시징 물건으로 나를 도움이)되었다. 당신이 제안한 것처럼, GetMessage 함수는 즉시 반환하지만 스레드 중단은, 사실, 메인 윈도우 메소드의 호출에 : 개체 : (추기경 EventMask)

procedure TMyThread.Execute; 
begin 
    while GetMessage(Msg, 0, 0, 0) and not Terminated do 
    begin 
    {thread message} 
    if Msg.hwnd = 0 then 
    begin 
     ... 
     if Assigned(FOnCommEventMethod) then 
     FOnCommEventMethod(FCommEventsQueueItem); 
     ... 
    end 
    else 
     DispatchMessage(Msg); 
    end; 
end; 

FOnCommEventMethod 프로 '로 선언 된 객체의 방법입니다 ; ' (이 스레드는 직렬 포트 이벤트를 처리합니다). 이 경우 FOnCommEventMethod에 주 양식 클래스에 속한 프로 시저가 지정되었습니다. 메서드가 내 스레드에서 호출 될 때 주 스레드가 작업을 마칠 때까지 스레드가 중단됩니다.

어째서? 보시다시피, 나는이 프로 시저를 호출하기 위해 Synchronize() 메서드를 사용하지 않습니다. 따라서 내 스레드가 주 스레드와 동기화 될 것으로 기대하지 않습니다. 그것은 암묵적으로 일어날 것인가? BTW, 모든 GUI 구성 요소는 다른 스레드가 아닌 주 스레드에 의해 액세스되어서는 안되기 때문에 Synchronize 메서드를 사용해야하지만 지금은 몇 가지 빠른 테스트 만하고 있습니다.

WaitForSingleObject 제목으로 되돌아 가면 사용할 수 없다는 것을 알지만 테스트 덕분에 (우연히) 문제를 발견했습니다.

도움 주셔서 감사합니다. 만약 당신이 나를 도와주지 않는다면, 아마도 메시징을 제거하고 대신 이벤트를 사용할 것입니다. 그리고 마침내 그것이 이유가 아님을 알게 될 것입니다 :-).

+0

스레드에서 동기화()를 사용합니까? – mghie

답변

3

는 메인 스레드가 작업을 완료하거나 Application.ProcessMessage를 메서드를 호출 할 경우에만, GetMessage 함수 반환을 수행하고 내 스레드는 일을 시작한다.

나는 이것이 실제로 일어난다는 것을 의심합니다. 두 메시지 루프는 SendMessage()과 같이 스레드를 동기화하는 다른 수단을 사용하지 않는 한 서로 독립적이어야합니다. 당신은 스레드가 실제로 GetMessage 함수()의 내부에 차단 않음을 확인하지 (sendMessage 첨부()를 내부적으로 사용) 동기화()의 내부 있습니까?

테스트 수행 주 스레드에서 WaitForSingleObject 함수를 사용하여 몇 초 동안 이벤트를 기다립니다.

당신이 당신의 GUI 부진이 나타날 것으로, 100 밀리 초를 말할 이상 시간 제한으로 메인 스레드에서 의 WaitForSingleObject()를 사용해서는 안됩니다. 사실 이것은 단순히 폴링이므로 주 스레드에서 전혀 사용하지 말라고 조언합니다. 대신 작업자 스레드의 메시지를 게시하십시오.

0

악마가 숨어있는 밥맛 세부 정보를 많이 떨어져 남겨 http://groups.google.com/group/borland.public.delphi.language.delphi.win32/browse_thread/thread/cf368834a606321b

요청 증류를 참조하십시오 후드 아래 많은 일들이 스레드 안전하지 않기 때문에 주 (또는 VCL) 스레드가 델파이에서 특별한을하고, 그것은 그들 모두를 소유하고 있습니다. 후드 아래의 VCL 스레드와 동기화되는 것들 때문에 메시지 루프와 같은 것이 기다리고 있습니다. 많은 사람들이 이것에 관한 이론을 가지고 있습니다. 가장 잘 작동하는 것으로 보이는 것은 VCL 스레드를 가능한 한 가볍게/응답으로 유지하여 대기 시간을 최소화하는 것입니다. 누구나 이것에 거의 동의합니다. 어떤 사람들에게는 효과가있는 다른 것들에 대한 아이디어가 있지만 다른 사람들은 단지 문제를 묻는 것이라고 생각합니다.

+0

그 스레드에는 27 개의 게시물이 있으며 그 중 많은 게시물이 오래되었습니다. 조금 더 증류 할 수 있니? –

2

스레드에 대한 메시지 큐를 만들 수 있습니다. 그냥 스레드에 다음 코드를 실행합니다

MSG msg; 
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); 
SetEvent(messageQueueReady); 
while (GetMessage(&msg, NULL, 0, 0)) 
{ 
    ...// do message processing here 
} 

를 PeekMessage에 대한 호출은 스레드에 대한 새 메시지 큐를 생성하기 위해 OS를 강제로. 메시지를이 스레드 (예 : PostThreadMessage를 통해)에 게시하기 전에 호출이 성공할 때까지 대기해야합니다 (예 : WaitForSingleObject를 통해). 이것이 위 예제에서 SetEvent API를 호출하는 이유입니다.

편집 : 예 : C로되어있어 죄송합니다. 괜찮습니다.

+0

이벤트 핸들에서 WaitForSingleObject()를 사용하면보다 정교한 방법으로 성공 여부를 확인하고 메시지를 휴면 및 재 게시하는 작업을 수행 할 수 있습니다. http://msdn.microsoft.com/en-us/library/ms644946(VS.85).aspx – mghie

+0

물론 물론 잠자기 및 설문 조사를 할 수 있지만 왜 WaitForSingleObject를 사용하지 않습니까? 이 질문에 – newgre

+0

+1이 생성 될 때까지 기다리는 가장 깨끗한 방법입니다. Windows가 메시지 대기열을 만들도록 강제하기 위해 'PeekMessage'에 마법의 호출을 수행하는 데 필요한 작업을 언급합니다. 그렇지 않으면'PostThreadMessage' 호출이 실패합니다. PostThreadMessage에 의해 보내지는 메시지는 윈도우와 관련이 없습니다. 일반적으로 윈도우와 관련이없는 메시지는 DispatchMessage 함수에 의해 발송 될 수 없습니다."* 귀하의 스레드가 MessageBox 대화 상자를 표시 할 수 없음을 의미합니다. –

관련 문제