2016-04-08 2 views
3

Ich habe eine MFC-C++ - Anwendung, wo mindestens zwei Threads "MainFrame" (= GUI-Thread) und einen "Solver" -Thread ausgeführt werden.C++ Wie kann ich auslösen, dass eine PostMessage in einem anderen Thread fortgesetzt wurde

An einem Punkt löst der zweite Thread (Solver) eine Änderung im Modell aus, die der GUI-Thread durch eine PostMessage(...) ausführen sollte. Um sicher zu sein, möchte ich warten, dass die Nachricht im zweiten Thread fortgesetzt wurde.

Mit Hilfe einer SendMessage(...) wartet der Solver-Thread auf die Ausführung der Nachricht, aber auf diese Weise umgehen wir die Nachrichtenwarteschlange, die nicht das Ziel sein sollte.

Meine Frage: Wie kann ich richtig und sauber überprüfen/auslösen, dass meine Nachricht fortgesetzt wurde, bevor ich fortfahre?

  1. Müssen wir alle 'x' Sekunden den Status der Haupt-Thread-Nachrichtenwarteschlange durch GetQueueStatus(...) überprüfen?
  2. Gibt es eine Möglichkeit, dass der Hauptthread ein "Erfolgsereignis" an den anderen Thread zurücksendet? Und dass der zweite wartet, um ein Ereignis zurück zu haben?
  3. Hat Boost eine einfache Lösung für diese Art von Problemen zur Verfügung gestellt?
  4. Gab es schon eine ähnliche Frage, die ich nicht gefunden habe? (Sorry)

Meine Funktion:

void PostSequencerMessageToGUI(ESequencerSignal signal, CSchedulerStep * step) 
{ 
    CMainFrame *mainFrame = theApp.GetMainFrame(); 
    assert(mainFrame); 
    if (!mainFrame) 
     return; 
    mainFrame->PostMessage(WM_SEQUENCER_SIGNAL, signal, reinterpret_cast<LPARAM>(step)); 
    // mainFrame->SendMessage(WM_SEQUENCER_SIGNAL, signal, reinterpret_cast<LPARAM>(step)); 

    // Message was posted, now wait for event back to continue procedure 
    // ... but how? ...and when to cancel ? ... 
    return; 
} 
+2

Der Fehler im Code ist. Wenn es darauf ankommt, ob eine Nachricht in die Nachrichtenwarteschlange gestellt oder direkt an die Fensterprozedur übergeben wird, haben Sie größere Probleme als diese. Wenn Sie etwas wie "PostMessage" mit einer Antwort wünschen, verwenden Sie [SendMessageCallback] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms644951.aspx). – IInspectable

+1

Verwenden Sie einfach ein Thread-Synchronisierungsobjekt, z. B. ein Autoreset-Ereignis, das Sie mit CreateEvent erstellen. Rufen Sie SetEvent() in dem UI-Thread auf, nachdem es die Nachricht verarbeitet hat. Und WaitForSingleObject() in Ihrem Arbeitsthread. Wenn Sie auch "Erfolg" zurückgeben müssen, fügen Sie bool oder int-Member zu CSchedulerStep hinzu. –

+0

Mit CreatEvent und SetEvent würde wahrscheinlich auch funktionieren. –

Antwort

0

Als Sendmessage die aktuelle Nachrichtenwarteschlange ignoriert (es die Warteschlange übergeben) i diesen Ansatz nicht nutzen konnte.

fand ich meine Lösung in einer anderen Frage, wo es eine Bedingungsvariablen gelöst wird mit und einem Mutex. https://stackoverflow.com/a/16909012/5036139

Meine Lösung:

#include <boost/thread/mutex.hpp> 
#include <boost/thread/thread.hpp> 
boost::condition_variable g_sequencerJobCondition; 
boost::mutex g_guiMutex; 

void PostSequencerMessageToGUI(ESequencerSignal signal, CSchedulerStep * step) 
{ 
    CMainFrame *mainFrame = theApp.GetMainFrame(); 
    assert(mainFrame); 
    if (!mainFrame) 
     return; 

    bool work_is_done = false; 

    try { 
     boost::mutex::scoped_lock lock(g_guiMutex); 
     mainFrame->PostMessage(WM_SEQUENCER_SIGNAL, reinterpret_cast<WPARAM>(&work_is_done), reinterpret_cast<LPARAM>(step)); 

     // Message was posted, now wait for event back to continue procedure 
     while (!work_is_done){ 
      g_sequencerJobCondition.wait(lock); 
     } 
    } 
    catch (... /*e*/){ 
     // Handle all kind of exception like boost::thread_resource_error, boost::thread_interrupted, boost::exception, std::exception 
     // ... 
    } 
    // ... 
    return; 
} 

Und

LRESULT CMainFrame::OnSequencerPostMessage(WPARAM wParam, LPARAM lParam) 
{ 
    // ... 
    bool *work_is_done = reinterpret_cast<bool*>(wParam); 
    CSchedulerStep* step = reinterpret_cast<CSchedulerStep*>(lParam); 

    // Handle business case ... 
    // ... 

    // Finally notify sequencer thread that the work is done 
    work_is_done = true; 
    g_sequencerJobCondition.notify_one(); 

    return true; 
} 
+0

Bitte fügen Sie die Lösung, die Sie gefunden haben, zu Ihrer Antwort hinzu. – Frits

Verwandte Themen