Problem mit Threading
-
Hallo,
ich habe mich ein bisschen mit Threading beschäftigt und ein kleines Programm zum testen geschrieben, jedoch funktioniert das gar nicht so wie ich mir das vorgestellt habe. Hier der Quellcode der cpp:
//--------------------------------------------------------------------------- #include <iostream> #include <vcl.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- DWORD dwThreadID1; HANDLE hThread1; DWORD dwThreadID2; HANDLE hThread2; //--------------------------------------------------------------------------- DWORD WINAPI ThreadFunc1(LPVOID lpParameter) { AllocConsole(); freopen("conin$", "r", stdin); freopen("conout$", "w", stdout); freopen("conout$", "w", stderr); while(1) { cout<<"Thread 1\n"; } return 0; } //--------------------------------------------------------------------------- DWORD WINAPI ThreadFunc2(LPVOID lpParameter) { AllocConsole(); freopen("conin$", "r", stdin); freopen("conout$", "w", stdout); freopen("conout$", "w", stderr); cout<<"Thread 2\n"; getchar(); return 0; } //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { hThread1 = CreateThread(0,0,ThreadFunc1,0,0,&dwThreadID1); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { TerminateThread(hThread1,0); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button3Click(TObject *Sender) { ExitThread(dwThreadID1); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button4Click(TObject *Sender) { hThread2 = CreateThread(0,0,ThreadFunc2,0,0,&dwThreadID2); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button5Click(TObject *Sender) { TerminateThread(hThread2,0); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button6Click(TObject *Sender) { ExitThread(dwThreadID2); } //---------------------------------------------------------------------------
Wie ich es mir vorgestellt hatte:
Beim Aufruf von Button1Click:
Eine Konsole wird aufgerufen, in der die ganze Zeit "Thread 1" ausgegeben wird.Beim Aufruf von Button2Click:
Die Schleife des ersten Threads wird angehalten.Beim Aufruf von Button3Click:
Die Konsole von Thread 1 wird geschlossen und Thread 1 wird beendet.Beim Aufruf von Button4Click:
Eine Konsole wird aufgerufen, in der "Thread 2" erscheint und die dann auf eine Tasteneingabe wartet und danach die Konsole schließt und den Thread beendet.Beim Aufruf von Button5Click:
Die getchar() Funktion wird unterbrochen und somit die Konsole geschlossen und der Thread beendet.Beim Aufruf von Button6Click:
Die Konsole von Thread 2 wird geschlossen und Thread 2 wird beendet.Was wirklich passiert:
Beim Aufruf von Button1Click:
Eine Konsole wird aufgerufen, in der die ganze Zeit "Thread 1" ausgegeben wird.
//So wie gedacht.Beim Aufruf von Button2Click:
Die Schleife des ersten Threads wird angehalten.
//Wieder so wie gedacht.Beim Aufruf von Button3Click:
Die Haupt-Form schließt sich, aber der Thread läuft weiter.Beim Aufruf von Button4Click:
Eine Konsole wird aufgerufen, in der "Thread 2" erscheint und die dann auf eine Tasteneingabe wartet, jedoch wird das Konsolenfenster nach der Tasteneingabe nicht beendet und der Thread läuft weiter.Beim Aufruf von Button5Click:
Thread 2 ist gestartet, aber nichts passiert.Beim Aufruf von Button6Click:
Dasselbe wie bei Button3Click. Selbst wenn kein Thread läuft, schließt sich die Haupt-Form, aber das Programm läuft weiter.Wenn ich Thread 1 gestartet habe, und versuche Thread 2 zu starten passiert nichts. Ist es nicht möglich zwei Konsolen zu öffnen?
Ich hoffe ihr könnt mir weiterhelfen.
Mit freundlichen Grüßen,
DarkBug
-
Vielleicht wäre es ratsam mal die Doku zu lesen.
- Zu Button 3+6:
ExitThread beendet den aktuellen Thread!
- zu Button 4:
Ich kenne die Innererien von Borland nicht und kann Dir zu den Input-Streams nichts sagen.
- zu Button 5:
Ich vermute mal, dss der Thread schon terminiert wird. Aber d.h. nicht das alle Fenster dieses Threads damit zerstört werden... Das kann es heißen, aber auch hier spielen die Borland Internas eine Rolle.
-
Ok, habe mir die Doku nun nochmal genauer durchgelesen. Damit ich das richtig verstanden habe:
1. Die ExitThread Funktion ist somit nicht nur gefährlich, sondern auch überflüssig, da man returnen kann?
2. Die TerminateThread Funktion sollte man nur in Notfällen benutzen bzw. wenn man komplette Kontrolle über den Code hat?3. Wie werte ich den returnten Wert eines Threads aus?
4. Wenn ich die ID des Threads sowie das Handle nicht benötige muss ich doch die beiden Variablen auch nicht anlegen oder?5. Ist folgender Code korrekt programmiert, so das auch keine Speicherlecks auftreten?
Thread 1 wird korrekt ausgeführt, aber Thread 2 bleibt komplett unausgeführt. Auch nachdem Thread 1 returned, macht Thread 2 nichts und nur der Process läuft weiter. Wo liegt der Fehler?//--------------------------------------------------------------------------- #include <windows.h> #include <iostream.h> #include <vcl.h> #pragma hdrstop //--------------------------------------------------------------------------- DWORD WINAPI ThreadFunc1(LPVOID lpParameter) { AllocConsole(); freopen("conin$", "r", stdin); freopen("conout$", "w", stdout); freopen("conout$", "w", stderr); for(int i=0;i<=9;i++) { cout<<"test\n"; } getchar(); FreeConsole(); return 0; } //--------------------------------------------------------------------------- DWORD WINAPI ThreadFunc2(LPVOID lpParameter) { ShowMessage("test"); return 0; } //--------------------------------------------------------------------------- #pragma argsused WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HANDLE hThread[2]; hThread[0] = CreateThread(NULL,0,ThreadFunc1,NULL,0,NULL); hThread[1] = CreateThread(NULL,0,ThreadFunc2,NULL,0,NULL); WaitForMultipleObjects(2,hThread,true,INFINITE); CloseHandle(hThread[0]); CloseHandle(hThread[1]); return 0; } //---------------------------------------------------------------------------
Mit freundlichen Grüßen,
DarkBug
-
3. GetExitCodeThread
-
zu 2. ExitThread ist nicht gefährlich. Aber wenn Du eine CRT/Framework benutzt wäre ein return eher ratsam. Denn dann läuft der Cleanup
zu 3. TerminateThread sollte man nie verwenden! Annahme Du terminierst einen Thread der gerade eine Systemressource geblockt hat, dann ist fini.
zu 4. Wenn Du nicht auf den Thead warten willst kannst Du das Handle schlieen. Nur weißt DU dann nie ob der Thread jemals seinen Job getan hat...
zu 5. Du müsstest mal im Borland Forum fagen wie das Threadlocal Storage ist. In einem MS Programm würde der Code ein Leak auslösen.
In einer MS Umgebung müsstest Du _beginthreadex oder AfxBeginThread verwenden.
http://blog.m-ri.de/index.php/2007/11/28/createthread-und-die-crt/
http://blog.m-ri.de/index.php/2008/02/28/afxbeginthread-versus-_beginthreadex/Was ist ShowMessage? Keine API Funktion. Du mischt hier WinAPI mit anderem Code. Die Seiteneffekte kann ich nicht abschätzen.
-
ShowMessage ist eine VCL Routine. Da die VCL aber nicht threadsafe ist, sollte solche Aufrufe mittels der Routine Synchronize synchronisiert werden.
-
Danke für eure Antworten. Leider bin ich nun ziemlich verwirrt. Von CRT und MFC habe ich noch nie etwas gehört. 1. Stimmen folgende Übersetzungen?:
CRT = C Run Time
MFC = Microsoft Foundation Classes2. Ich benutze die CRT wenn ich eine C Librarie verwende?
3. Ich benutze doch somit meistens die C++ Run Time, da man meistens neue Funktionen (C++) verwendet, oder?
4. Oder gilt die C++ Run Time mit als C Run Time?
5. Die CRT würde ich zum Beispiel benutzen, würde ich mit Sockets arbeiten, da Sockets in C geschrieben sind, oder?
6. Sobald ich eine GUI verwende, verwende ich die MFC?
7. Ich programmiere hauptsächlich GUI-Programme und Programme die im Hintergrund laufen sowie Socket Code enthalten. Somit wäre es doch am sinnvollsten nur AfxBeginThread zu benutzen, oder?
8. Da ich _beginthreadex nicht im Zusammenhang mit GUIs verwenden darf oder?
9. Wenn ich ein Handle eines Threads schließen möchte, der gerade Code ausführt, läuft beim ersten Versuch der Code weiter und beim zweiten Versuch bekomme ich eine "Externe Exception", da das Handle wahrscheinlich schon geschlossen ist. Meine Frage war eigentlich: Muss man unbedingt ein Handle erstellen, wenn man einen Thread erstellt, also auch wenn man das Handle nicht benötigt?
10. Welche Funktion benutzt man denn normalerweise um dem User eine Fehlermeldung anzeigen zu lassen? Ich benutze:
-ShowMessage(Fehlerausgabe);
-Application->MessageBox(Fehlerausgabe,Fenstername,MB_OK | MB_ICONERROR);
11. Was ist eine "Routine Synchronize" und wie funktioniert das?
-
Ich kann nur für die MS-Compiler und Produkte sprechen. Mit dem Borland Kram kenne ich mich nicht aus. Entsprechend habe ich geantwortet.
Auch meine Artikel behandel nur VC!
Dir MFC ist ein Microsoft Produkt undhat nicht mit Borland zu tn.Aber auch bei Borland musst Du wohl oder übel eine CRT nutzen.
Das sind aber Fragen die hier in Windows API falsch sind. Das gehört in das Borland Forum.Ich verschiebe mal...
-
Dieser Thread wurde von Moderator/in Martin Richter aus dem Forum WinAPI in das Forum VCL (C++ Builder) verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
Hallo
Ich empfehle dir komplett in VCL zu arbeiten, dort gibt es auch eine Thread-Klasse. Hier ist ein Tutorial, das deine Fragen beantworten sollte.
bis bald
akari
-
@Martin Richter: Könntest du meine Fragen auf die MS-Compiler bezogen beantworten?
@akari: Vielen Dank, ich habe mir das Tutorial gerade durchgelesen und versuche mich da mal genauer hineinzufinden.