thread Verständnisfrage



  • Hallo,

    ich habe zwei Verständnisfragen bezüglich Threads in C++ unter Windows.
    Zum einen hab ich in allen Tutorials dir auf Kommunikation zwischen Threads eingingen gelesen, dass es schneller und effizienter wäre gemeinsame Variablen (bzw Adressräume) zu nutzen als die üblichen Verdächtigen der Prozesskommunikation (pipes, etc).
    Schön und gut, aber wie kann und darf ich mir das konkret in C++ Source vorstellen?

    Dann noch eine andere Verständnisfrage.... Ich erzeuge 2 Threads, einer startet sofort, und der andere Suspended.... beim Versuch diesen mittels .ResumeThread() zu erwecken bekomme ich eine Fehlermeldung, wo nach meinem Verständnis her alles seine Richtigkeit haben sollte. (Liegt wohl ein Verständnisfehler vor. :D)

    error: request for member `ResumeThread' in `threads[1]', which is of non-aggregate type `void*'
    

    Hier mal mein Beispielcode....

    #include <string.h>
    #include <windows.h>
    #include <iostream>
    using namespace std;
    
    DWORD WINAPI threada(PVOID pParam)
    {
    	string s, fuerb;
    	s = *(string*)pParam;
    	cout <<"von Main:"<<s<<endl;
    
    	fuerb = s + " mir gehts gut";  //das moechte ich an Prozess B "schicken"
    	return 0;
    }
    
    DWORD WINAPI threadb(PVOID pParam)
    {
    	string s;
    	s = *(string*)pParam;
    	cout <<"von Main:"<<s<<endl;
    
    	cout <<"von Prozess A:???"<<endl; //wie bekomme ich den Inhalt von threada::fuerb ?
    	return 0;
    }
    
    int main()
    {
    	HANDLE threads[2];
    	string s;
    	unsigned long id;
    	s="Hallo Welt,";
    
    	threads[0] = CreateThread(NULL, 0, threada, &s, 0, &id);
    	threads[1] = CreateThread(NULL, 0, threadb, &s, CREATE_SUSPENDED, &id);
    	WaitForMultipleObjects(2, threads, FALSE, INFINITE);
    
    	threads[1].ResumeThread();//error: request for member `ResumeThread' in `threads[1]', which is of non-aggregate type `void*'
    	WaitForMultipleObjects(1, threads, FALSE, INFINITE);
    	return 0;
    }
    

    Hat jemand Zeit und Lust mir zu helfen?
    Compiler:MinGW
    OS: Win32

    Gruss
    Robin



  • 1. Du kannst z.B. in beiden Threads folgendes machen:

    DWORD WINAPI thread(LPVOID param)
    {
      string* s=(string*)param;
      ...
    }
    

    Da greifen dann beide Threads auf den selben String aus deinem Hauptprogramm zu (jeweils über s->tuwas() oder (*s)[i]='a'). Allerdings brauchst du dafür dann Synchronisationsmechanismen (Critical Section), um die Zugriffe gegeneinander zu schützen.

    2. "threads" ist ein Array von HANDLE's - die verweisen zwar intern auf die Kontrollstruktur eines Threads, sind aber an sich keine Objekte. Zum Glück gibt es eine globale Funktion ResumeThread, die du stattdessen verwenden kannst:

    ResumeThread(threads[1]);
    

    PS: Die WaitForMultipleObjects()-Aufrufe stimmen auch noch nicht ganz - im zweiten Aufruf wartest du auf threads[0], aber der ist zu dem Zeitpunkt längst beendet.



  • Ok, danke.
    Das gibt mir weitere Anhaltspunkte zum selbsständigen Suchen...

    Wenn ich aber nun mehr als nur einen String übergeben will, kann ich das dann mit einem Zeiger auf ein Struct, welches alles enthält was ich übergeben möchte, machen? Oder gibt es da eine elegantere Lösung?

    Gruss
    R



  • std::Robin schrieb:

    Wenn ich aber nun mehr als nur einen String übergeben will, kann ich das dann mit einem Zeiger auf ein Struct, welches alles enthält was ich übergeben möchte, machen? Oder gibt es da eine elegantere Lösung?

    Ja, das geht - und ist die eleganteste Lösung, wenn Variablen nur in Richtung Sub-Thread übergeben werden sollen. Die Übergabevariable erzeugst Du vorzugsweise mit new oder malloc und zerstörst sie dann nach Verwendung im Sub-Thread. So vermeidest Du auf einfache Weise race-conditions (unsynchronisierte Zugriffe auf die Variablen).



  • Ok, dann werde - um ganz sicher zu gehen also in der main ein Objekt mittels new dynamsich erzeugen und einen Zeiger darauf übergeben. Innerhalb des Threads müsste ich doch theoretisch darin ohne Probleme herummachen können...
    Beim Beenden des Threads wird das Objekt dann mit delete gelöscht.

    Ist das richtig so?



  • Ja.



  • Wichtig ist natürlich, dass Du das erzeugte Objekt nach Erzeugen des Sub-Threads im Haupt-Thread nicht mehr anrührst.



  • std::Robin schrieb:

    Beim Beenden des Threads wird das Objekt dann mit delete gelöscht.

    Noch besser ist es womöglich, wenn der Thread das Objekt selber entsorgt, wenn er es nicht mehr braucht.



  • CStoll schrieb:

    std::Robin schrieb:

    Beim Beenden des Threads wird das Objekt dann mit delete gelöscht.

    Noch besser ist es womöglich, wenn der Thread das Objekt selber entsorgt, wenn er es nicht mehr braucht.

    So war es gemeint und wurde es (denke ich) auch verstanden.



  • Hmm, eigentlich wollte gerade dazu übergehen ich dieses Objekt auch dazu zu gebrauchen Rückgabewerte zu übergeben....

    Spricht denn da was dagegen?

    Gruss
    R



  • @mgs: Da habe ich mich wohl etwas verlesen.

    @Robin: Nein, da spricht nichts dagegen. Du mußt nur dem Hauptthread irgendwie mitteilen, wann das Ergebnis jetzt vorliegt (z.B. in einer eigenen bool-Variable oder über Synch-Objekte (d.h. das Thread-Ende oder einen Hilfsevent per WaitFor...() abfangen)).
    Und du benötigst eine gemeinsame Critical Section, über die du die Zugriffe auf dein Objekt koordinierst.



  • std::Robin schrieb:

    Hmm, eigentlich wollte gerade dazu übergehen ich dieses Objekt auch dazu zu gebrauchen Rückgabewerte zu übergeben....

    Sofern Du nicht ständig neue Sub-Threads mit neuen Variablen erzeugst, würde ich in diesem Fall eher eine globale Variable empfehlen mit Synchronization durch CriticalSections. Gibt weniger Zuständigkeitsprobleme beim Zerstören der (sonst dynamisch erzeugten) Variablen-Objekte.

    Signalisierung von Statusänderungen der Worker-Threads lassen sich in Windows-Programmen (mit Message-Queue) sehr schön durch PostMessage an den Haupt-Thread übermitteln. Einfache int-Ergebnisse können so gleich mit übermittelt werden.


Log in to reply