Laden...

Destruktoren und Threads

Erstellt von Tankian vor 19 Jahren Letzter Beitrag vor 19 Jahren 2.784 Views
T
Tankian Themenstarter:in
81 Beiträge seit 2004
vor 19 Jahren
Destruktoren und Threads

using System;
using System.Threading;

public class Element
{
  private Thread thread;
  private string id;
	
  public Element(string s)
  {
    id = s;
			
    Console.WriteLine("Element.Element(): {0}", id);		
		
    thread = new Thread(new ThreadStart(F));
    thread.Start();
  }
	
  ~Element()
  {
    thread.Abort();
		
    Console.WriteLine("Element.~Element(): {0}", id);
  }
	
  private void F()
  {
    while(Thread.CurrentThread.IsAlive)
    {
      Console.WriteLine("Thread von {0} lebt noch .. ", id);
      Thread.Sleep(1000);
    }
  }
	
  public static void Main()
  {
    Element a = new Element("a");
    a = null;
		
    GC.Collect();
    GC.WaitForPendingFinalizers();
		
    Console.WriteLine("collected");
  }
}

Ausgabe:
Element.Element(): a
collected
Thread von a lebt noch ..
Thread von a lebt noch ..
Thread von a lebt noch ..
Thread von a lebt noch ..
Thread von a lebt noch ..
.
.
.

Problem erkannt ? Genau, der Destruktor wird nie aufgerufen
(oder ich hab noch nie lang genug gewartet, bezweifel ich aber doch sehr stark).

Mir is schon klar, dass es mit nem using() und ner Implementierung von
IDisposable.Dispose() funktionieren würde, allerdings wär a dann read-only.

Mir gings bei dem Test nur darum zu überprüfen ob bei einem operator= auch
Destruktoren aufgerufen werden, wahrscheinlich normalerweise schon, nur hier
irgendwie nicht. Jetzt müsste ich dann selbst vor jedem operator= ein .Dispose()
schreiben, wenn ich das vergesse hab ich schon Probleme -> nicht gut.

Außerdem is es mir auch egal, wann der Destruktor aufgerufen wird, hauptsächlich
in annähender Zukunft. Das sah ich als "philosphischen Grund" gegen Dispose.

Muss doch irgendeine schöne und vor allem idiotensichere Lösung geben.
Danke.

C
980 Beiträge seit 2003
vor 19 Jahren

Wie sollte der Deconstructor auch aufgerufen werden wenn die laufende Methode des anderen Threads noch immer implizit die Instanz referenziert (du kannst ja in der Methode auf die Klassenmembers zugreifen)? Kleiner Denkfehler?

F
529 Beiträge seit 2003
vor 19 Jahren

Wenn du einen Thread töten willst machst du das so:


private void F()
{
        try
        {
                while(true) //Das Thread.IsAlive ist fürn Eimer weil der Thread nix mehr tuen würde währe er nicht alive
                {
                        Console.WriteLine("Thread von {0} lebt noch .. ", id);
                        Thread.Sleep(1000);
                }
        }
         catch(ThreadAbortException)
        {
               Console.WriteLine("Jetzt wird der Thread gestoppt");
               //return; Für den Notfall, sollte auch ohne gehen
        }
         //Oder
        catch(ThreadInterruptedException) //Weiß nicht ob das richtig geschrieben wird
        {
               Console.WriteLine("Jetzt wird der Thread abgebrochen");
               //return;
        }
}

Du sagt zwar dem Thread, dass er sich abbrechen soll. Der Thread bekommt auch die Threadabortexception, aber er kann sie ja nicht abfangen und weiß daher auch nicht, dass erbrechen soll. Nun bekommt der Thread die Threadabortexception und springt deshalb aus der Whileschleife aus.

Besuchen sie das VisualC++ - Forum

T
Tankian Themenstarter:in
81 Beiträge seit 2004
vor 19 Jahren

Original von cdr
Wie sollte der Deconstructor auch aufgerufen werden wenn die laufende Methode des anderen Threads noch immer implizit die Instanz referenziert (du kannst ja in der Methode auf die Klassenmembers zugreifen)? Kleiner Denkfehler?

Jo, stimmt eigentlich.

Mit nem public static void F() funktioniert es auch so,
wie ich es mir eigentlich gedacht hatte.

Danke 🙂

C
980 Beiträge seit 2003
vor 19 Jahren

Original von Franknstein
Der Thread bekommt auch die Threadabortexception, aber er kann sie ja nicht abfangen und weiß daher auch nicht, dass erbrechen soll. Nun bekommt der Thread die Threadabortexception und springt deshalb aus der Whileschleife aus.

Wenn ein Thread eine Exception nicht behandelt (gilt für ALLE exceptions, so auch für ThreadAbortException), dann wird er automatisch gekillt. Is es der Hauptthread erhälst du dann eine schöne Fehlermeldung ... allerdings kann die CLR keine Threads killen die auf ein Win32 Ereignis warten (z.b. WaitForSingleObject syscall), eine Abort Exception wird dort erst wirksam sobald der Syscall zurückkehrt (darum funktioniert Abort auch nicht in allen Fällen, meist kann man dann aber z.b. mit Win32 timeouts arbeiten) ...

F
529 Beiträge seit 2003
vor 19 Jahren

Hm,
Ich hatte des früheren in einem Programm das Problem, dass sich der Thread ums Verecken nicht mit Thread.Abort hat beenden lassen. Seitdem ich das aber so mache, wie ich das beschrieben habe, hatte ich nie wieder so Probleme....
Lag warscheinlich daran, dass ich die Exception innerhalb der while-Schleife abgefangen habe, und nicht die Schleife unterbrochen habe.... kann das sein?

Besuchen sie das VisualC++ - Forum

C
980 Beiträge seit 2003
vor 19 Jahren

Ja, tönt wahrscheinlich. Ein Thread wird nur beendet wenn die Methode normal ausläuft (mittels return oder keinen weiteren instruktionen mehr) oder wenn eine Exception auftritt die nicht abgefangen wird. (Abort und Interrupt provozieren solche Exceptions, mehr können sie aber auch nicht ausrichten!)