Multi-Thread Programmierung
-
Hallo zusammen,
wie versprochen hier nochmal eine Frage zu der Multi-Thread Programmierung.
Habe mich mit dem hier im Tutorial beschriebenen Weg zur Thread-Programmierung auseinandergesetzt.
Zu meinem Problem:
Ich benötige einen zweiten Thread, um eine .dll zu laden und auf den Rückgabewert zu warten.
Habe das ganze mal exemplarisch ausprobiert, habe aber noch Probleme den Thread ordnungsgemäß zu schließen.
Hier der Code
//UNIT 1 //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include "Unit2.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { TmyThread *FNewThread = new TmyThread(false); } //---------------------------------------------------------------------------//UNIT 2 //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit2.h" #include "Unit1.h" #include "vektor.h" #pragma package(smart_init) //--------------------------------------------------------------------------- __fastcall TmyThread::TmyThread(bool CreateSuspended) : TThread(CreateSuspended) { FreeOnTerminate = true; } //--------------------------------------------------------------------------- void __fastcall TmyThread::Execute() { if(!mclInitializeApplication(NULL,0)) Form1->EditMCR->Text = IntToStr(0); else Form1->EditMCR->Text = IntToStr(1); mxArray *x; mxArray *y; int nargout = 1; mxArray *tp = NULL; double x_value[] = {1,2,3,4,5}; double y_value[] = {2,3,4,6,7}; x = mxCreateDoubleMatrix(1,5,mxREAL); memcpy(mxGetPr(x), x_value, 5*sizeof(double)); y = mxCreateDoubleMatrix(1,5,mxREAL); memcpy(mxGetPr(y), y_value, 5*sizeof(double)); if(!vektorInitialize()) Form1->EditDLL->Text = IntToStr(0); else Form1->EditDLL->Text = IntToStr(1); mlfVektor(nargout, &tp, x, y); mxDestroyArray(x); x = 0; mxDestroyArray(y); y = 0; mxDestroyArray(tp); tp = 0; } //---------------------------------------------------------------------------Es funktioniert soweit. Einerseits das laden der MCR
"mclInitializeApplication(NULL,0)", sowie das Laden der eigentlichen .dll
"vektorInitialize()".Jetzt benötige ich nur noch eine Hilfestellung.
1. Wie setze ich die Methode Synchronize() ein, und wie schließe ich den zweiten Thread ordnungsgemäß.
So wie es im Tutorial beschrieben ist, funktioniert das nicht.LG
Todd
-
Die Execute-Methode wird einmalig aufgerufen, d.h. solange du da keine Schleife drin hast, wird der Thread nach dem Abarbeiten der Funktion wieder zerstört.
Du mußt nur, die Methode auslagern, um Synchronize aufrufen zu können:
void __fastcall TmyThread::Execute() { Synchronize(MyExecute); } void __fastcall TmyThread::MyExecute() { if(!mclInitializeApplication(NULL,0)) Form1->EditMCR->Text = IntToStr(0); else Form1->EditMCR->Text = IntToStr(1); // ... }
-
Danke für deine Antwort,
wenn ich das so mache, dann "friert" meine Anwendung ein, solange ich mich in der MyExecute von TmyThread befinde.
Woran kann das liegen?
LG
Todd
-
C++Builder-Dokumentation schrieb:
Die Methode Synchronize führt innerhalb des VCL-Haupt-Threads einen Methodenaufruf aus.
-
Hallo,
Die Methode Synchronize führt innerhalb des VCL-Haupt-Threads einen Methodenaufruf aus.
Das sagt mir leider nichts. Wie kann ich denn verhindern, dass mir das ganze einfriert?
Brauche ich die Synchronize Methode überhaupt?Danke
Todd
-
Todd schrieb:
Wie kann ich denn verhindern, dass mir das ganze einfriert?
Nicht Synchronize() benutzen. Was du dort als Argument übergibst, wird im Hauptthread, also demjenigen, der für die Benutzerinteraktion zuständig ist, ausgeführt, und wenn der mit dem Ausführen deiner Funktion beschäftigt ist, kann er eben nicht mit dem Benutzer interagieren

Synchronize() benutzt man i.d.R. nur, um auf nicht threadsichere Funktionen wie die der visuellen Komponenten der VCL zuzugreifen, also z.B., wenn der Thread nach dem Beenden seiner Aufgabe das Ergebnis in ein Memo eintragen will.
-
Okay,
danke. Jetzt verstehe ich es.
Wie kann ich aber verhindern, dass innerhalb des zweiten Thread's etwas schief geht und er aus diesem nicht mehr heraus kommt.
Wenn zum Beispiel innerhalb der .dll ein Berechnungsfehler vorliegt und nicht mehr aus dieser herausfindet.
Gibt es eine Rücksicherung für solche Fälle?
LG
Todd
-
Du kannst dem Benutzer die Möglichkeit geben, den Thread zu terminieren, falls ihm die Wartezeit zu lange wird, z.B. mittels TerminateThread oder KillThrd.
-
Danke für deine Antwort.
Kann man denn überprüfen, ob ein Thread noch läuft?
Gibt es hierfür vielleicht schon eine eingebaute Funktion?LG
Todd
-
da du das selfdestruct gewählt hast, wird das schwierig, FreeOnTerminate bewirkt das dein Zeiger ins nichts verweist ... wenn du aber darauf verzichtest, kannst du z.B. im c-tor des thread eine variable bool finished mit false initialisieren und die kurz vorm verlassen der execute auf true setzen, in deinem programm kannst du dann einfach diese variable abrufen und dann den thread sauber "von hand" deleten
ansonsten kannst du ja den d-tor des thread überschreiben und ein signal an deine hauptklasse liefern (dann gehts auch mit freeonterminate = true)
ich spinn hier mal was zusammen, du machst n neues Form auf (showmodal) mit text "Aufruf wird bearbeitet", startest in dem form den thread und übergibst ihm einen pointer auf das form, wenn die execute beendet setzt du im d-tor des thread einfach das modalresult des Form auf OK. dann könntest auch nen abbruch button unterbringen
-
Ich würde dem Thread im Konstruktor eine Callback-Funktion mit übergeben, welche dem Hauptthread das beenden signalisiert. Aufgerufen wird die dann im Destruktor. Dabei muß der eigentliche Thread auch nichts genaues vom Hauptthread wissen.
Bei mir hat eine deratige Funktion immer folgende Signaturtypedef void CloseCallback(unsigned int, TForm*);DDie Funktion kann man dann im Hauptthread global oder als statische Memberfunktion der Form definieren.
Auf die Art braucht man kein Include des Header der Hauptform im Thread.
-
Danke für deine Antwort.
Werde dem Hinweis nachgehen und mich evtl. zur gegebenen Zeit wieder melden.
Liebe Grüße
Todd