Imperator Katarn
2006-02-23, 16:57:37
Hi Leute,
Ich arbeitete kürzlich an folgendem Problem:
Ein Worker-Thread sendet eine Nachricht an den Hauptthread, daß dieser eine bestimmte Aktion ausführen soll, und soll dann warten bis der Hauptthread die Aktion durchgeführt hat. Zuerst habe ich eine Realisierung mittels WaitForSingleObject versucht:
HANDLE hEvent;
CMainWnd cMainWnd;
// im Worker-Thread:
// Event erzeugen und mit non-signaled initialisieren
hEvent = CreateEvent(NULL, TRUE, FALSE, "Action finished");
// Nachricht an Programmfenster (kontrolliert vom Hauptthread) senden,
// daß Aktion ausgeführt werden soll
cMainWnd->PostMessage(/*starte Aktion*/);
// auf Beenden der Aktion warten
WaitForSingleObject(hEvent, INFINITE);
// im Hauptthread:
// Funktion, die durch die Nachricht aufgerufen wird
CMainWnd::DoAction()
{
// mache irgendwas...
// Event auf signaled setzen
SetEvent(hEvent);
}
Wenn im Hauptthread hEvent auf signaled gesetzt wird, sollte im Worker-Thread WaitForSingleObject zurückkehren. Nach einigem Experimentieren stellte ich jedoch fest, daß WaitForSingleObject des öfteren schon vorher zurückkehrte, als hEvent noch auf non-signaled stand!
Versuchsweise rief ich nach CreateEvent nochmal extra ResetEvent(hEvent) auf, um hEvent nur ja sicher auf non-signaled zu haben, was aber auch nichts brachte.
Dann probierte ich eine Alternative aus mit CSingleLock::Lock statt WaitForSingleObject:
CEvent *pEvent; // ersetzt hEvent
CMainWnd cMainWnd;
// im Worker-Thread:
// Event erzeugen und mit non-signaled initialisieren
pEvent = new CEvent(FALSE, TRUE, "Action finished", NULL);
pEvent->ResetEvent();
// Nachricht an Programmfenster (kontrolliert vom Hauptthread) senden,
// daß Aktion ausgeführt werden soll
cMainWnd->PostMessage(/*starte Aktion*/);
// auf Beenden der Aktion warten
CSingleLock cSingleLock(pEvent);
cSingleLock.Lock(); // ersetzt WaitForSingleObject
// im Hauptthread:
// Funktion, die durch die Nachricht aufgerufen wird
CMainWnd::DoAction()
{
// mache irgendwas...
// Event auf signaled setzen
pEvent->SetEvent();
}
und so funktioniert es einwandfrei. CSingleLock::Lock im Worker-Thread wartet stets brav darauf, daß das Ereignis im Hauptthread auf signaled gesetzt wird.
Die Frage, die ich mir stelle, ist nun: warum funktioniert die erstere Variante nicht, die zweite dagegen wohl?
Die zweite Variante nutzt die Klassen CEvent und CSingleLock aus der MFC, diese aber baut doch auf der Win32 API auf, so daß die Annahme naheliegend erscheint, daß CSingleLock::Lock nichts anderes als ein WaitForSingleObject macht und CEvent nichts weiter tut als mit einem Event-Handle zu hantieren.
Die zweite Variante soll daher doch eigentlich genau das gleiche tun wie die erste, oder?
Ich arbeitete kürzlich an folgendem Problem:
Ein Worker-Thread sendet eine Nachricht an den Hauptthread, daß dieser eine bestimmte Aktion ausführen soll, und soll dann warten bis der Hauptthread die Aktion durchgeführt hat. Zuerst habe ich eine Realisierung mittels WaitForSingleObject versucht:
HANDLE hEvent;
CMainWnd cMainWnd;
// im Worker-Thread:
// Event erzeugen und mit non-signaled initialisieren
hEvent = CreateEvent(NULL, TRUE, FALSE, "Action finished");
// Nachricht an Programmfenster (kontrolliert vom Hauptthread) senden,
// daß Aktion ausgeführt werden soll
cMainWnd->PostMessage(/*starte Aktion*/);
// auf Beenden der Aktion warten
WaitForSingleObject(hEvent, INFINITE);
// im Hauptthread:
// Funktion, die durch die Nachricht aufgerufen wird
CMainWnd::DoAction()
{
// mache irgendwas...
// Event auf signaled setzen
SetEvent(hEvent);
}
Wenn im Hauptthread hEvent auf signaled gesetzt wird, sollte im Worker-Thread WaitForSingleObject zurückkehren. Nach einigem Experimentieren stellte ich jedoch fest, daß WaitForSingleObject des öfteren schon vorher zurückkehrte, als hEvent noch auf non-signaled stand!
Versuchsweise rief ich nach CreateEvent nochmal extra ResetEvent(hEvent) auf, um hEvent nur ja sicher auf non-signaled zu haben, was aber auch nichts brachte.
Dann probierte ich eine Alternative aus mit CSingleLock::Lock statt WaitForSingleObject:
CEvent *pEvent; // ersetzt hEvent
CMainWnd cMainWnd;
// im Worker-Thread:
// Event erzeugen und mit non-signaled initialisieren
pEvent = new CEvent(FALSE, TRUE, "Action finished", NULL);
pEvent->ResetEvent();
// Nachricht an Programmfenster (kontrolliert vom Hauptthread) senden,
// daß Aktion ausgeführt werden soll
cMainWnd->PostMessage(/*starte Aktion*/);
// auf Beenden der Aktion warten
CSingleLock cSingleLock(pEvent);
cSingleLock.Lock(); // ersetzt WaitForSingleObject
// im Hauptthread:
// Funktion, die durch die Nachricht aufgerufen wird
CMainWnd::DoAction()
{
// mache irgendwas...
// Event auf signaled setzen
pEvent->SetEvent();
}
und so funktioniert es einwandfrei. CSingleLock::Lock im Worker-Thread wartet stets brav darauf, daß das Ereignis im Hauptthread auf signaled gesetzt wird.
Die Frage, die ich mir stelle, ist nun: warum funktioniert die erstere Variante nicht, die zweite dagegen wohl?
Die zweite Variante nutzt die Klassen CEvent und CSingleLock aus der MFC, diese aber baut doch auf der Win32 API auf, so daß die Annahme naheliegend erscheint, daß CSingleLock::Lock nichts anderes als ein WaitForSingleObject macht und CEvent nichts weiter tut als mit einem Event-Handle zu hantieren.
Die zweite Variante soll daher doch eigentlich genau das gleiche tun wie die erste, oder?