2009-09-22 8 views
7

J'ai un thread graphique principal que je veux rester sensible à l'action des utilisateurs, comme le déplacement de la boîte de dialogue, le redimensionnement, etc. alors que j'ai un thread d'arrière-plan qui effectue une tâche. Dans le passé, j'ai utilisé WaitForSingleObject avec un timeout pour traiter les événements gui en attendant que le thread d'arrière-plan se termine. J'ai récemment lu à propos de MsgWaitForMultipleObjects qui semblait résoudre le problème que j'avais un peu plus propre.Comprendre MsgWaitForMultipleObjects

Quelqu'un peut-il me dire les bugs dans le code suivant & où je vais mal ici? Le GUI ne répond pas lorsque je clique sur le bouton pour démarrer le fil. J'ai fait une application de dialogue avec un avi qui joue sur le fil de l'ui principal. J'ai un bouton pour démarrer un thread et utiliser MsgWaitForMultipleObjects pour attendre sur le handle de thread, mais permettre à tous les messages à travers pour être finalement brisé lorsque le thread est terminé/signalé.

Merci.

UINT MyThreadProc(LPVOID pParam) 
{ 
    ThreadData* pObject = (ThreadData*)pParam; 

    if (pObject == NULL || 
     !pObject->IsKindOf(RUNTIME_CLASS(ThreadData))) 
    return 1; 

    // Do some processing. 
    int x = 0; 
    while (x++ < 5000) 
    { 
     for (int i=0; i<50000; i++) 
      double sum = sqrt((double)i+1) * sqrt((double)i+2); 
    } 

    return 0; 
} 

bouton Gestionnaire

void Cmsgwait_demoDlg::OnBnClickedBtnStartThread() 
{ 
    m_pThreadData = new ThreadData; 
    CWinThread* pWorkThread = AfxBeginThread(MyThreadProc, m_pThreadData); 

    m_status.SetWindowText("Status: Waiting for thread to complete."); 

    HANDLE handles[] = { pWorkThread->m_hThread }; 
    DWORD ret = 0; 

    do 
    { 
     ret = MsgWaitForMultipleObjects(1, handles, FALSE, INFINITE, QS_ALLINPUT); 
     if (ret == WAIT_OBJECT_0) 
     { 
      m_status.SetWindowText("Status: Thread completed."); 
     } 
     else if (WAIT_IO_COMPLETION) 
     { 
      m_status.SetWindowText("Status: User mode APC queued."); 
     } 
     else if (WAIT_FAILED) 
     { 
      m_status.SetWindowText("Status: Wait failed"); 
     } 
    } 
    while (ret != WAIT_OBJECT_0 && ret != WAIT_FAILED); 
} 

Répondre

13

Vous n'êtes pas en train de traiter le message entrant du thread d'interface utilisateur, prendre à look at Raymond's blog (voir aussi here) pour un échantillon.

while (true) { 
    switch (MsgWaitForMultipleObjects(1, &h, 
         FALSE, INFINITE, QS_ALLINPUT)) { 
    case WAIT_OBJECT_0: 
     DoSomethingWith(h); // event has been signalled 
     break; 
    case WAIT_OBJECT_0+1: 
     // we have a message - peek and dispatch it 
     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { 
     // TODO: must handle WM_QUIT; see Raymond's blog for details 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
     } 
     break; 
    default: 
     return FALSE; // unexpected failure 
    } 
    } 
+0

Ouais ce serait ça. Merci. –

+3

DANGER Ceci est le code qui a le bug sur lequel Raymond a écrit. Vous devez boucler sur le peekmessage. –

+2

5 upvotes et l'échantillon a quelques bugs dangereux ... corrigés (sans offenser l'auteur original). –