2016-06-22 9 views
1

In meiner MFC-Anwendung habe ich einen Worker-Thread, der eine Netzwerkverbindung abhört und sobald einige Informationen angekommen sind, rufe ich SendMessageToDescendants an, um diese Informationen über den Lparam-Parameter zu senden. Daher wird jedes Rahmenfenster die Nachricht erhalten und möglicherweise über einen Nachrichtenhandler für die Nachricht WM_SYNCHRONOTIFICATION (WM_SYNCHRONOTIFICATION ist eine WM_APP+x Nachricht) verarbeiten.Verwenden von SendMessageToDescendants zwischen Threads

-Code in dem Arbeitsthread: (der Kürze halber vereinfacht)

while (TRUE) 
{ 
    CNotificationMessage notificationmessage; 
    Listen(&notificationmessage); // blocking until some information arrives 

    m_pMainWnd->SendMessageToDescendants(WM_SYNCHRONOTIFICATION, NULL, (LPARAM)(newnotif)); 

    // have all OnSynchroNotification handlers been called here ? 
} 

Message handler im Hauptthread:

LRESULT CMyFrame::OnSynchroNotification(WPARAM p1, LPARAM p2) 
{ 
    CNotificationMessage *pNotification = (CNotificationMessage*)p2; 

    // process message (ommited for brevity) 
} 

Der Code funktioniert gut, aber ich bin nicht sicher, wenn bei der Rückkehr von SendMessageToDescendants alle OnSynchroNotification aufgerufen wurden.

+4

[niemals Sendmessage Vielfalt nutzen aus einem Thread] (http://stackoverflow.com/a/29603742/17034). –

Antwort

2

Die einfachste Lösung ist ein Zähler. Bevor Sie aufrufen, initialisieren Sie einen gemeinsamen Zähler mit der Anzahl der untergeordneten Fenster, die Sie die Nachricht verarbeiten möchten. Jeder Nachrichtenhandler ist dann dafür verantwortlich, den Zähler zu dekrementieren, wenn er seine Arbeit beendet hat, und Ihre Ereignisschleife kann prüfen, ob der Zähler 0 ist, bevor weitere Ereignisse erzeugt werden. In Pseudo-C++:

unsigned int sharedCount; // global/static shared value 

while (TRUE) 
{ 
    CNotificationMessage notificationmessage; 
    Listen(&notificationmessage); // blocking until some information arrives 

    unsigned int current = InterlockedCompareExchange(&sharedCount, activeWindowCount, 0); 
    if (current == 0) 
    { 
     m_pMainWnd->SendMessageToDescendants(WM_SYNCHRONOTIFICATION, NULL, (LPARAM)(newnotif)); 
    } 
    else 
    { 
     // Still processing the last message. 
    } 

    while (InterlockedCompareExchange(&sharedCount, 0, 0) != 0) 
    { 
     Sleep(100); 
    } 
} 

LRESULT CMyFrame::OnSynchroNotification(WPARAM p1, LPARAM p2) 
{ 
    // Processing 
    InterlockedDecrement(&sharedCount); 
} 

Die etwas komplexere Lösung, aber die, die ich persönlich bevorzugen, da Sie nach Abschluss nicht CPU verbrennen müssen warten, ist ein Ereignis für jedes Nachrichtenverarbeitungsfenster zu erstellen, und dann Verwenden Sie WaitForMultipleObjects (oder die Ex-Version), um die Ereignisschleife bis zum Abschluss zu stoppen. Wieder ++ in pseudo C:

while (TRUE) 
{ 
    CNotificationMessage notificationmessage; 
    Listen(&notificationmessage); // blocking until some information arrives 

    m_pMainWnd->SendMessageToDescendants(WM_SYNCHRONOTIFICATION, NULL, (LPARAM)(newnotif)); 

    DWORD waitResult = WaitForMultipleObjects(activeWindowCount, FrameEvents, TRUE, INFINITE); 
    if (waitResult == WAIT_OBJECT_0) 
    { 
     // Success 
    } 
    else if (waitResult == WAIT_FAILED) 
    { 
     // Failure: Use GetLastError() to figure out why the function call failed. 
    } 

    // Reset the events 
}  

LRESULT CMyFrame::OnSynchroNotification(WPARAM p1, LPARAM p2) 
{ 
    // Processing 
    SetEvent(thisFramesEvent); 
} 

In diesem Beispiel wird ein Endlos-Timeout, aber Sie können einen angemessenen Timeout, und prüfen, ob der Rückgabewert WAIT_TIMEOUT zu sehen, wenn die Zeit abgelaufen ist immer gesetzt.

(Erforderlich Haftungsausschluss: Fehlerprüfung und Variableninitialisierung haben aus diesen beiden Gründen der Kürze und Lesbarkeit entfernt finden Sie in der Dokumentation nach, wie auf Fehler überprüfen..)

Verwandte Themen