Überprüfen ob Thread fertig ist?



  • Hi Leute !

    Wie kann ich überprüfen ob ein Thread, den ich manuel gestartet habe, schon fertig ist?

    Also so in der richtung

    while (!Thread1.Finished) {
    }
    
    ...
    

    Solange warten bis Thread fertig -> dann weiter arbeiten!?

    Das ganze wird benötigt, da ich in der while() dann Application.DoEvents() (o.ä.) einbauen will, da die Funktion die in dem neuen Thread abgearbeitet wird etwas länger dauert (>1 minute) -> das hat den nachteil das die GUI sonst nicht mehr reagieren würde !

    Gibt es eine ander alternative bzw, kann man es besser lösen?

    Danke im vorraus !



  • Ähm … dadurch verlierst Du doch aber jeden Nutzen, den Du durch die Verwendung von Threads erst bekommen hast. Wieso also nicht gleich den Thread weglassen?



  • naja! die funktion die ich aufrufe ist ja blockierend! (ist eine c++ Fkt. die mit einem ext. gerät kommuniziert)
    Das ext. Gerät brauch > 1 minute bis es daten zurückschickt -> sprich: solange läuft eine while() Schleife !

    Während diese schleife läuft -> blockiert ja die GUI!

    Meine idee: einen Thread starten -> in dieser den Befehl aufrufen -> der thread kann ja ruhig warten!
    und im main-thread mache ich eine while() die solange läuft bis der thread fertig ist -> in die while packe ich dan Application.DoEvents() -> jetzt kann ich während der dauer von >1 Minute andere events verwenden (das wichstigste ist ja onPaint -> da sonst die GUI 1 minute nicht reagieren würde)

    Ist klar geworden was ich bezwecken will?

    Gibts alternativen?

    Lg



  • thread schrieb:

    und im main-thread mache ich eine while() die solange läuft bis der thread fertig ist -> in die while packe ich dan Application.DoEvents() -> jetzt kann ich während der dauer von >1 Minute andere events verwenden (das wichstigste ist ja onPaint -> da sonst die GUI 1 minute nicht reagieren würde)

    Problem: das ganze ist extreeem prozessorlastig.

    Gibts alternativen?

    Klar. Optimal wäre es, die *gesamte* Verarbeitung in einen anderen Thread auszulagern (z.B. per Backgroundworker). Dann kannst Du Dir die Schleife komplett sparen, denn Du bist nicht darauf angewiesen zu erfahren, wann der Thread beendet.

    Also, mal allgemein gehalten, Du hast zur Zeit folgenden Code (oder so):

    private void someButton_Click(object sender, EventArgs e) {
        DoSomething1();
    
        Thread t = new Thread(DeineKomischeCFunktion);
        t.Start();
    
        while (t.ThreadState == ThreadState.Running)
            Application.DoEvents();
    
        DoSomething2();
    }
    

    Das ist schlecht. Besser wäre folgendes:

    private void someButton_Click(object sender, EventArgs e) {
        Thread t = new Thread(Machwas);
        t.Start();
    }
    
    private void Machwas() {
        DoSomething1();
        DeineKomischeCFunktion();
        DoSomething2();
    }
    


  • Achja, stimmt! so geht's natürlich besser! dann is es mir egal wann das ding fertig ist 😉 Schreib das erhaltene Paket einfach im Thread in die Textbox und aus! 😉

    DANKE



  • Thread schrieb:

    Achja, stimmt! so geht's natürlich besser! dann is es mir egal wann das ding fertig ist 😉 Schreib das erhaltene Paket einfach im Thread in die Textbox und aus! 😉

    DANKE

    Dabei musst Du aber beachten das Forms nicht Multithreading-tauglich ist. Du darfst also nicht aus einem anderem Thread einfach in die Textbox schreiben. Das kann (und wird meistens) zu Abstürzen führen.

    Um das sauber zu lösen gibt es die Funktionen InvokeRequired() und Invoke()



  • skals schrieb:

    Thread schrieb:

    Achja, stimmt! so geht's natürlich besser! dann is es mir egal wann das ding fertig ist 😉 Schreib das erhaltene Paket einfach im Thread in die Textbox und aus! 😉

    DANKE

    Dabei musst Du aber beachten das Forms nicht Multithreading-tauglich ist. Du darfst also nicht aus einem anderem Thread einfach in die Textbox schreiben. Das kann (und wird meistens) zu Abstürzen führen.

    Um das sauber zu lösen gibt es die Funktionen InvokeRequired() und Invoke()

    Warum führt dies zu Abstürzen? Ist es nicht egal aus welchen Thread ich zB in eine Textbox schreibe? Warum?



  • Thread schrieb:

    Warum führt dies zu Abstürzen? Ist es nicht egal aus welchen Thread ich zB in eine Textbox schreibe? Warum?

    Nein, das ist nicht egal, weil diese Operation einfach nicht definiert ist. Aber das Problem lässt sich recht einfach lösen, wie skals schon angedeutet hat:

    // aus diesem Code:
    void ChangeText(string txt) {
        textBox1.Text = txt;
    }
    
    // wird:
    
    void ChangeText(string txt) {
        if (InvokeRequired) {
            Invoke(new Action<string>(Changetext), txt);
            return;
        }
        textBox1.Text = txt;
    }
    

    Man muss halt nur für jede Methodensignatur einen passenden Delegaten verwenden (hier System.Action<T>).



  • Irgendwie check ich das ganze nicht!

    private void btnStart_Click(object sender, EventArgs e) {
       Thread thread = new Thread(new ThreadStart(DoIt));
       thread.Start();
    
    }
    
    private void DoIt () {
    
       // bla bla bla
       Wo schreibe ich in die Textbox bzw. Änderen die Enabled eigenschaft des Buttons?
    }
    


  • Es funktioniert aber ohne Probleme:

    private void btnStart_Click(object sender, EventArgs 
    {
         Thread thread = new Thread(new ThreadStart(DoIt));
    				btnStart.Enabled = false;
    
         thread.Start();
    }
    
    void DoIt() {
       Thread.Sleep(5000);
       this.btnStart.Enabled = true;
    }
    

    In diesem beispiel kann ich ja auch auf den Button zugreifen? Wieso sollte das nicht funktionieren bzw. zu einem Fehler führen?



  • Thread schrieb:

    Es funktioniert aber ohne Probleme:

    private void btnStart_Click(object sender, EventArgs 
    {
         Thread thread = new Thread(new ThreadStart(DoIt));
    				btnStart.Enabled = false;
    
         thread.Start();
    }
    
    void DoIt() {
       Thread.Sleep(5000);
       this.btnStart.Enabled = true;
    }
    

    In diesem beispiel kann ich ja auch auf den Button zugreifen? Wieso sollte das nicht funktionieren bzw. zu einem Fehler führen?

    Ok, dann mach es halt so und viel Spaß bei der Fehlersuche wenn Deine Programme irgebndwann anfangen seltsame Abstürze zu zeigen die Du Dir nciht erklären kannst. Wer nicht hören will, muß fühlen heisst es schließlich nicht zu unrecht.

    Nur weil etwas zufällig keinen Fehler zeigt ist es noch LANGE nicht richtig, gerade bei Fehlern im Bezug auf Multithreading heisst das Stichwort Race-Condition (http://en.wikipedia.org/wiki/Race_condition).

    In der MSDN gibt es ausführliche Artikel zum Thema Multithreading + Forms (z.B. http://www.microsoft.com/germany/msdn/library/net/SicheresUndEinfachesMultithreadingInWindowsForms.mspx?mfr=true). Aber wenn Du es besser weisst, ok, dann können wir hier dir auch nicht weiterhelfen, denn dann bist Du auf jeden Fall viel weiter als wir hier.



  • Thread schrieb:

    In diesem beispiel kann ich ja auch auf den Button zugreifen?

    Welchen Wert hat denn bei Dir 'CheckForIllegalCrossThreadCalls'? Dieser Wert sollte *immer* 'true' sein, bei Dir scheint er 'false' zu sein, sonst dürfte das nicht funktionieren.



  • Das erkennt leider auch nicht alle Fehlbedienungen. Ich schließe mich auf jeden Fall der Empfehlung an, Invoke zu verwenden. Noch besser ist es, den BackgroundWorker zu verwenden, der legt den Hintergrund-Thread automatisch an und man hat einen Handler im richtigen Thread, der bei Abschluss aufgerufen wird.



  • Danke für eure Hilfe! Habs jetzt richtig implementiert (mit InvokeRequired, etc.)

    Nun stellt sich eine andere frage: wenn die Form geschlossen wird -> läuft ja der erzeugte Thread trotzdem noch weiter!

    Wie kann ich sicher gehen das der Thread beendet wird, wen ich die Form schließe?

    Danke



  • Thread schrieb:

    Wie kann ich sicher gehen das der Thread beendet wird, wen ich die Form schließe?

    Speicher Dir einfach den Thread als eine private Instanz in der Form und beende ihn im 'Closed'-Event der Form:

    private void Form1_FormClosed(object sender, FormClosedEventArgs e) {
        if (m_Thread != null && m_Thread.IsAlive)
            m_Thread.Join();
    }
    


  • Oder alternativ einfach thread.IsBackground auf true setzen. Background threads werden automatisch beendet wenn das Programm terminiert.


Anmelden zum Antworten