Hilfe bei Threads!!!
-
Ja ich hab es selber gefunden, sorry hab die Frage (wohl aus Bequemlichkeit) zu früh gestellt!
ich versuch zu warten (WaitforSingleObject) bis der Thread fertig ist
und dann beenden. Funktioniert aber nicht!!void CDlgAnalogIn::OnOK() { m_thread_active=false; b_running=false; CString warning= "Fehler Thread nicht beendet"; if(WAIT_TIMEOUT == WaitForSingleObject(m_xDisplayThread, 5000)) { AfxMessageBox(warning, MB_OK); } else { AfxEndThread((unsigned int)thread_function, NULL); CDialog::OnCancel(); } //CDialog::OnOK(); }
das mit der variable m_thread_active funktioniert auch nicht!
} void CDlgAnalogIn::SetValue() { p_ai->sum=0; float value; if(m_thread_active) { while(b_running) { Sleep(500); value=(p_ai->ReadAnalogPort()); m_data=value; PostMessage(WM_DATACHANGED); } } // else // AfxEndThread((unsigned int)thread_function, NULL); }
-
Falscher Parameter für AfxEndThread() - du bist im Thread deiner Thread-Function, also brauchst du deren Adresse nicht mehr anzugeben. Schreib doch einfach "AfxEndThread(0);"
Oder sogar noch einfacher - teste die Abbruchbedingung direkt in der Thread-Funktion:
UINT thread_func(LPVOID Param) { CDlgAnalogIn* reciever=(CDlgAnalogIn*)Param; while(reciever->m_thread_active) { float val=ReadAnalogPort(); reciever->SetValue(val); } }
-
tja ich bin dir da schon zuvor gekommen:
//Thread starten UINT CDlgAnalogIn::thread_function(LPVOID pParam) { CDlgAnalogIn* pDlg = (CDlgAnalogIn*) pParam; if(pDlg->m_thread_active) { pDlg->SetValue(); } else AfxEndThread(0); return 0; }
-
Dir ist aber klar, daß diese Funktion genau einen Wert von deinem Analogport liest und dann den Thread wieder beendet? Für so etwas sind eigenlich keine eigenständigen Threads notwendig.
-
Sorry, ich hab das falsche kopiert....
es sieht natürlich so aus:
//Thread starten UINT CDlgAnalogIn::thread_function(LPVOID pParam) { CDlgAnalogIn* pDlg = (CDlgAnalogIn*) pParam; while(pDlg->m_thread_active) { pDlg->SetValue(); } //AfxEndThread(0); return 0; }
Berechnung:
void CDlgAnalogIn::SetValue() { p_ai->sum=0; float value; Sleep(100); value=(p_ai->ReadAnalogPort()); m_data=value; PostMessage(WM_DATACHANGED); }
dazu mein beenden Methode:
void CDlgAnalogIn::OnOK() { m_thread_active=false; b_running=false; CString warning= "Fehler Thread nicht beendet"; // WaitForSingleObject(m_xDisplayThread, 5000); AfxEndThread(0); CDialog::OnOK();
Was jetzt passiert verwirrt mich allerdings:
das Auslesen funktionirt wunderbar,
sobald ich auf OK klicke, wird m_thread_active auf false gesetzt, dann springt er plötzlich in Set value, springt dann wieder in OnOk, geht auf AfxEndThread, springt dann wieder in SetValue und stürzt dann natürlich ab da Thread ja beendet!!!
-
Du mußt AfxEndThread() immer aus dem Thread heraus aufrufen, den du gerade beendest (return in der Thread-Funktion hat den selben Effekt) - also ist der Aufruf in der OnOK()-Methode überflüssig (und beendet vermutlich den Hauptthread deines Programms).
PS: Und es wäre eine gute Idee, die gegenseitigen Elementzugriffe mit einer CriticalSection voreinander abzuschirmen - es kann sehr unangenehm werden, wenn du mit halbfertig geschriebenen Daten arbeiten willst.
-
so Probblem:
ich setz die bool m_thred_active auf false,
dann wird die while - schleife beendet und er geht auf return 0 und dann auf OnDialog:Ok und verlässt den Dialog, ist in meinem Hauptfenster und geht dann noch mal auf SetValue() und postMessage und stürzt dann natürlich ab!Warum springt er trotz Thread beenden und Dialog schließen noch mal in die SetValue- Methode??????
//Thread starten UINT CDlgAnalogIn::thread_function(LPVOID pParam) { CDlgAnalogIn* pDlg = (CDlgAnalogIn*) pParam; while(pDlg->m_thread_active) { pDlg->SetValue(); } return 0; }[cpp]void CDlgAnalogIn::OnOK() { m_thread_active=false; b_running=false; thread_function(this); // WaitForSingleObject(m_xDisplayThread, 5000); // delete m_xDisplayThread; //AfxEndThread(0); CDialog::OnOK(); }
-
So hab jetzt die Lösung (für denjenigen den es interessiert):
void CDlgAnalogIn::OnBUTTONStop() { DWORD state; m_thread_active=false; b_running=false; state=WaitForSingleObject(*m_xDisplayThread, 1000); if(state==WAIT_TIMEOUT) { //Thread läuft noch Thread beenden OnBUTTONStop(); } else//thread läuft nicht -> Dialog verlassen CDialog::OnOK(); }
beim Drücken von Stop soll der Dialog beendet werden und das Einlesen des AnalogPorts auch.
Zuerst werden die Flags auf False gesetzt
Dann kommt eine Abfrage ob sich der Thread noch "meldet"
wenn ja nochmal Zeit geben um ausstehende Operationen durchzuführen,
andernfalls kann man den Dialog beenden da der Thread zu ende ist.
-
Du solltest lieber mit einer while-Schleife arbeiten, anstatt Dich selber rekursiv aufzurufen, da bei langen Wartezeiten u.U. der Stack überlaufen kann.
Und selbst die while-Schleife sollte nach gewisser Zeit abbrechen, falls sich der Thread aufgehangen hat.
-
Ein Klassen von CWinThread braucht nicht unbedingt ein Fenster.
http://www.c-plusplus.net/forum/viewtopic-var-t-is-39101.html
Der Fehler bei SetOwner war: Du hast deine Analogklasse genommen. SetOwner soll aber den Zeiger auf das Hauptfenster setzen.In der Threadklasse gibt es eine Funktion Run.
Da geht der Thread rein wenn er gestartet wird. Run läßt sich einfach über den Assi einfügen.In Run da
int Cthreadklassevoncwinthread::Run() { //Deine Funktionen Hier wird mitgeteilt das sich der Thread nun beendet PostQuitMessage(0); return 1; }
Im Dlg kann man dann mit
DWORD exitcodethread; if (GetExitCodeThread(m_plibThread->m_hThread, &exitcodethread) && exitcodethread == STILL_ACTIVE) { // Thread läuft noch } else { // Thread hat sich beendet }
abfragen ob der Thread noch läuft.
Im Thread hat man mit
m_pOwner->
zugriff auf den Dialog. Vorsicht: nicht threadsicher
Im Thread selbst kannst du dann eine Instanz deiner Analogklasse erstellen und damit machen was du willst.
Wenn du später mal aus der Analogklasse auf deinen Dialog was ausgeben willst (Status) dann ist das denke ich der beste Weg. Mit einem Workerthread ist das zwar auch möglich aber etwas komlexer.