Multithreading: Msgs zwischen Threads
-
SeverinK schrieb:
Wenn ich dem 2. Thread die ID des ersten Thread übergebe, könnte ich ja postThreadMessage() verwenden, oder ?
Ich müsste nur ein Struct erstellen, welches die Thread ID und einen anderes Objekt enthält, da ich dem 2. Thread noch was andres übergeben muss.Der Empfänger-Thread braucht auf jeden Fall eine Message-Queue, sonst wird PostThreadMessage() scheitern. Außerdem kannst du mit PostThreadMessage() keine lokalen Daten übergeben (z.B. den Pointer auf eine struct), da der Aufruf asynchron ist und eine lokale struct nicht mehr existiert, wenn die Message bearbeitet wird.
Wäre es nicht einfacher mit Event-Objekten zu arbeiten? Das fände ich "natürlicher", falls deine Threads nicht ohnehin Messages verarbeiten. Kuck mal nach CreateEvent() und WaitForSingleObject().
Stefan.
-
Hallo,
Danke für den Vorschlag, Stefan!Ich habe mich nun ein wenig eingelesen und hätte nun folgende Idee:
Thread A erstellt ein event und eine instanz von klasse B (die brauch ich um in klasse B non static zugreifen zu können).
Die beiden werden dann in ein struct gepackt, und der Funktion von Thread B übergeben (welcher in Thread A erstellt wird)
In Thread B wird dann der Algorithmus durchlaufen und immer wenn es notwendig ist, wird das Event gesetzt. Soweit ich das verstanden habe, kann das event beliebig oft mit SetEvent() getriggert werden, oder?
Thread A merkt das dann mit WaitForSingleObject() und kann eine funktion in Klasse B aufrufen, welche das Objekt, das in Klasse B gefüllt wurde, zurückgibt.
-
SeverinK schrieb:
Hallo,
Danke für den Vorschlag, Stefan!Ich habe mich nun ein wenig eingelesen und hätte nun folgende Idee:
Thread A erstellt ein event und eine instanz von klasse B (die brauch ich um in klasse B non static zugreifen zu können).
Die beiden werden dann in ein struct gepackt, und der Funktion von Thread B übergeben (welcher in Thread A erstellt wird)
In Thread B wird dann der Algorithmus durchlaufen und immer wenn es notwendig ist, wird das Event gesetzt. Soweit ich das verstanden habe, kann das event beliebig oft mit SetEvent() getriggert werden, oder?
Thread A merkt das dann mit WaitForSingleObject() und kann eine funktion in Klasse B aufrufen, welche das Objekt, das in Klasse B gefüllt wurde, zurückgibt.
Öhöm --- ich hab mir das jetzt dreimal durchgelesen und versteh's nicht. Kein Kommentar also

Stefan.
-
hmmm

Dann versuch ichs nochmal (hoffentlich besser verständlich)
Thread A erstellt eine Instanz von Klasse B und ein neues event.
Diese Instanz und das Event packe ich dann in ein Struct.dann erstell ich in Thread A einen neuen Thread und übergebe an die Threadfunction dieses Threads den pointer zu dem vorher definierten Struct.
in dem neuen Thread (die Funktion ist in Klasse
mach ich dann wieder ein
Struct aus dem übergebenen pointer und kann somit das event auslösen, oder ?Dadurch dass in der Thread Funktion in Klasse B dann das event ausgelöst wird, welches in Thread A erstellt wurde, kann ich in Thread A mit WaitForSinlgeObject() darauf reagieren und in diesem Fall eine Funktion in Klasse B aufrufen, welche ein Objekt zurückgibt, welches in Thread B initialisiert wurde.
-
Hallo,
Das ist jetz das struct, welches an die threadFunction übergeben werden soll
typedef struct threadObject{ ClassB* cB; HANDLE* event; };In Klasse A hab ich jetzt folgendes in einem bereits laufendem thread:
DWORD WINAPI ClassA::threadForReq(LPVOID data){ ClassA* cA= (ClassA*) data; ClassB cB; HANDLE event; event = CreateEvent(NULL, FALSE, FALSE, 0); threadObject to = {&cB, &event}; HANDLE secondThread; secondThread = (HANDLE) CreateThread(NULL,0, cB.threadFunction, (void*) &to, 0, NULL); DWORD temp = WaitForSingleObject(event, INFINITE); switch (temp) { case WAIT_OBJECT_0: { //doStuff } } return ((DWORD) data); }Und das ist die threadFunction in ClassB nur um zu testen ob das SetEvent funktioniert:
DWORD WINAPI ClassB::threadFunction(LPVOID data) { threadObject* to = (threadObject*) data; ClassB* cB= to->cB; HANDLE* event = to->event; Sleep(1000); //do some stuff SetEvent(event); return ((DWORD) data); }Aber er kommt nie bis zum case WAIT_OBJECT_0
In dem Beispiel [url] http://msdn.microsoft.com/en-us/library/ms686915(VS.85).aspx [/url] wird das aber genauso gemacht, nur halt innerhalb einer KlasseWas hab ich da jetzt übersehn ?

Vielen Dank im Voraus,
Severin
-
DWORD WINAPI ClassB::threadFunction(LPVOID data) { threadObject* to = (threadObject*) data; ClassB* cB= to->cB; HANDLE* event = to->event; Sleep(1000); //do some stuff // SetEvent(event); // falsch - lässt sich aber dummerweise compilieren, da man void** (==HANDLE*) nach void* (==HANDLE) konvertieren kann SetEvent(*event); // richtig // oder halt so: HANDLE event2 = *(to->event); SetEvent(event2); return ((DWORD) data); }
-
Aaaaaah, das wars.. vielen dank

Das event sollte ja nach einmal SetEvent wieder auf "false" sein, oder ?
irgendwie stürzt mein programm wahllos ab und es scheint so, als würde
WaitForSingleObject öfters getriggert, obwohl ich nicht mal ne schleife oder ähnliches gebaut habe.
-
SeverinK schrieb:
Das event sollte ja nach einmal SetEvent wieder auf "false" sein, oder ?
ein auto-reset-event geht auf non-signaled sobald ein thread aufgeweckt wurde. das musst nicht mit dem zeitpunkt zusammenstimmen wo SetEvent aufgerufen wurde, denn es muss ja gerade kein thread da sein der wartet.
und ein manual-reset event bleibt sowieso signaled.
irgendwie stürzt mein programm wahllos ab und es scheint so, als würde
WaitForSingleObject öfters getriggert, obwohl ich nicht mal ne schleife oder ähnliches gebaut habe.aha
-
SeverinK schrieb:
Aber er kommt nie bis zum case WAIT_OBJECT_0
Das sollte dir zu denken geben. Wie wär's mit einem Test auf WAIT_FAILED und Auswertung von GetLastError()? Fehlerbehandlung ist manchmal ne ganz gute Idee.
SeverinK schrieb:
irgendwie stürzt mein programm wahllos ab und es scheint so, als würde
WaitForSingleObject öfters getriggert, obwohl ich nicht mal ne schleife oder ähnliches gebaut habe."Stürzt wahllos ab" ist nicht wirklich eine erschöpfende Beschreibung. Kriegst du Meldungen? Falls ja, welche?
Und lebt das an den Thread übergebene Objekt wirklich lange genug? Immerhin legst du es in einer Funktion als lokales Objekt an! Mach mal eine globale Variable daraus - nur zum Testen - oder verwende new(). Wenns dann keine Abstürze mehr gibt (oder andere
) bist du vielleicht einen Schritt weiter.Stefan.
-
DStefan schrieb:
"Stürzt wahllos ab" ist nicht wirklich eine erschöpfende Beschreibung. Kriegst du Meldungen? Falls ja, welche?
Und lebt das an den Thread übergebene Objekt wirklich lange genug? Immerhin legst du es in einer Funktion als lokales Objekt an! Mach mal eine globale Variable daraus - nur zum Testen - oder verwende new(). Wenns dann keine Abstürze mehr gibt (oder andere
) bist du vielleicht einen Schritt weiter.Stefan.
"Stürzt wahllos ab" is leider das einzige was ich dazu sagen kann, weil sich mein IDE (omnet++) aufhängt und die meldung bekomme "Project.exe reagiert nicht mehr".
Auch im debug modus kann ich nicht mehr herausfinden.Wenn ich das projekt zum 1. mal starte läuft es durch. wenn ich es dann stoppe und gleich wieder starte hängt es sich auf.
-
Ich habe den Thread und das Event jetzt global gemacht, aber es ist immer noch wie zuvor:
Ich starte das programm das 1. mal und es läuft. Starte ich es danach gleich nochmal, hängt es sich einfach auf ohne eine Fehlermeldung oder sonstiges auszugeben.
Auch im debugger kann ich nicht eingrenzen wo genau der Fehler auftritt
-
Dann hilft dir vielleicht ein Trace weiter: Erstelle dir einen globalen std::ofstream auf eine Datei deiner Wahl. Schreibe an kritischen Stellen Trace-Einträge in den Stream. Wenn das Programm abgestürzt ist, solltest du zumindest herausfinden können, was es zuvor gemacht hat. Etwa so:
#include <fstream> std::ofstream trace("c:\\dev\\myprogram\\trace.txt"); void func() { trace << GetCurrentThreadId() << ": func() 0" << std::endl; bar(); trace << GetCurrentThreadId() << ": func() 1" << std::endl; DWORD rc = WaitForSingleObject(); trace << GetCurrentThreadId() << ": func() 2" << std::endl; // ... usw. trace << GetCurrentThreadId() << ": func() exit" << std::endl; }Indem du mit GetCurrentThreadId() immer die Thread-Id davor schreibst, weißt du, welcher Thread was gemacht hat.
Das Problem mit dem Trace ist natürlich, dass er möglicherweise das Programm so verlangsamt, dass die Fehler nicht mehr auftreten. Einen Versuch ist es aber vielleicht wert.
Stefan.
-
Danke für die Antwort!
bevor ich das mache, hab ich mal einfach einige zeilen auskommentiert und bin dadurch jetz darauf gekommen, dass das Thread erstellen manachmal einfach nicht funktioniert

Also das Thread erstellen läuft ja bereits in ner Threadfunktion eines anderen Threads.
Dieser erste Thread wird noch ohne probleme erstellt, und nur wenn ich
HANDLE secondThread; secondThread = (HANDLE) CreateThread(NULL,0, cB.threadFunction, (void*) &to, 0, NULL);auskommentiere läuft er auch durch. Lass ich dieses CreateThread stehen, kommt es zu dem Fehler (wie gesagt, nicht immer..) Auch wenn ich in der threadFunction dieses secondThreads gar nichts mache, den Thread also nur erstelle, kommt es zu dem Fehler. Das selbe, wenn ich als Parameter nicht das struct sondern gar nichts übergebe.
Ich brauche aber den zweiten Thread in dem ersten Thread, sonst kann ich nicht umsetzen, was ich geplant habe.
Vielen Dank für die Hilfe,
Severin