Entwickler-Ecke

Basistechnologien - Methoden als eigenen Thread mit Timeout starten


Laurence - Mi 10.02.10 10:02
Titel: Methoden als eigenen Thread mit Timeout starten
Hallo und guten morgen ihr alle da draußen!

Ich hab ein Problem, bzw. mehrere Probleme. Ich möchte was mit Threads lösen, weiß aber nicht wie!
Und zwar habe ich eine Liste von Objekten, wo jedes mal die Methode perform ausgeführt werden soll.
Bis dahin funktioniert auch alles.
Nun möchte ich jedoch, falls die Methode zu lange läuft, dass sie
abgebrochen wird, wie z.B. kopieren von großen Ordnern über ein langsames Netzwerk (Timeout).

Ich habe mir gedacht, dass ich das als Thread löse, jedoch habe ich davon leider keine Ahnung! :-(

Habe den etwas vereinfachten Quelltext wie es momentan ist, unten.

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
public class Example
{
  public List<Worker> Workers = new List<Worker>();  //Liste, die "worker" Objekte enthaelt

  public bool Execute() {
    bool OperationSuccessful = true;   //Gibt an, ob alle Aufgaben erfolgreich verlaufen sind

    foreach (Worker wo in Workers) {
      if (wo.perform() == false) {
        OperationSuccessful = false;
      } else { }
  }
}


Hatte es mal mit Threads probiert, jedoch muss der Returnwert anscheinend VOID sein.

C#-Quelltext
1:
Thread mythread = new Thread(this.Workers[0]perform);                    

Vielen Dank für eure Hilfe
Gruß Laurence


JüTho - Mi 10.02.10 10:17

Hallo,

mein Vorschlag ist, dass du dich zunächst um einen Thread kümmerst, damit du die Zusammenarbeit zwischen Programm und getrennten Threads kennenlernst. Noch besser gefällt mir der BackgroundWorker, weil der die wichtigsten Schritte kapselt und deshalb einfacher zu bedienen ist. Ein schönes Beispiel ist in der SDK-Doku/MSDN/Hilfe zu finden.

Wenn das erledigt ist, sollte es kein Problem sein, mehrere solcher Threads bzw. worker zusammenzufassen.

Gruß Jürgen


danielf - Mi 10.02.10 10:57

Hallo,

einen TimeOut kannst du so realisieren, dass die Methode parallel startest aber dann wiederum auf sie wartest (joinst). Die join-Methode hat einen Parameter TimeOut. Wenn dieser Abgelaufen ist oder die Methode zu ende ist wird dein Code fortgesetzt. Da musst du dann unterscheiden ob der Thread beendet wurde oder der TimeOut erreicht wurde und dementsprechend reagieren.

Gruß Daniel

Edit: Googel findet folgendes Link [http://dotnet-snippets.de/dns/die-ausfuehrungszeit-einer-methode-einschraenken-SID723.aspx].


Laurence - Mi 10.02.10 11:23

danielf: Also dieses Beispiel habe ich auch schon gefunden und versucht einzubinden.

Jedoch bekomme ich bei folgendem Aufruf...

C#-Quelltext
1:
2:
3:
TimeOut to = new TimeOut();
if (!to.DoIt(new RunMethodDelegate(wo.perform()), TimeSpan.FromSeconds(2)))
{...}

...die Fehlermeldung:
bool Worker.perform()' has the wrong return type

Was mach ich falsch, oder wie gehts richtig?
Danke


danielf - Mi 10.02.10 11:37

Die RunMethodDelegate erwartet keinen Wert sondern einen "Funktionspointer". D.h. lass die Klammern weg, dann sollte es gehen.


Laurence - Mi 10.02.10 11:40

user profile icondanielf hat folgendes geschrieben Zum zitierten Posting springen:
Die RunMethodDelegate erwartet keinen Wert sondern einen "Funktionspointer". D.h. lass die Klammern weg, dann sollte es gehen.


Oh sorry, das war mein Fehler, die Klammer gehört nicht hin

C#-Quelltext
1:
2:
3:
TimeOut to = new TimeOut();
if (!to.DoIt(new RunMethodDelegate(wo.perform), TimeSpan.FromSeconds(2)))
{...}


danielf - Mi 10.02.10 11:55

Hmm.. beim genaueren betrachten ist der Code nicht mehr einleuchtend :)



C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
            Program p = new Program(); 
            Thread t = new Thread(new ParameterizedThreadStart(p.DoSomething));

            t.Start();

            t.Join(TimeSpan.FromSeconds(2));

            if (t.ThreadState != System.Threading.ThreadState.Stopped)
            {
                MessageBox.Show("TimeOut!");
                t.Abort();
            }


So finde ich es eigentlich logischer.


Laurence - Mi 10.02.10 12:12

Ja ist es auf jeden Fall!
Bis dahin war ich auch schon mal vor ewigen Zeiten gekommen, bis mich dann der Fehler
No overload for 'perform' matches delegate 'System.Threading.ParameterizedThreadStart'
abgeschreckt hatte. Hattes es daraufhin mit dem BackgroundWorker und dieser tollen Klasse probiert.


danielf - Mi 10.02.10 12:14

Aber nun gehts? Oder fehlt dir noch was?

Du solltest alle Bauteile haben.


Laurence - Mi 10.02.10 12:33

Nene, geht nun, siehe:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
Thread t = new Thread(new ParameterizedThreadStart(delegate { act.perform(); }));
t.Start();
t.Join(TimeSpan.FromSeconds(2));
if (t.ThreadState != System.Threading.ThreadState.Stopped) {
  MessageBox.Show("TimeOut!");
  t.Abort();
}


Nur leider klappt das t.Abort() nicht, bzw. es klappt bestimmt schon, nur bei meiner Methode nicht


danielf - Mi 10.02.10 12:35

Das t.Abort löst in dem Thread ein Exception aus (ThreadAbortException). Wenn du diese (oder generell Exception) in deiner Methode abfängst dann bleibt der Thread aktiv.


Laurence - Mi 10.02.10 14:04

hat nun funktioniert, das Exception Handling hatte nur irgendwie so gut gegriffen! :-)


danielf - Mi 10.02.10 14:06

Das bezweifle ich, wenn es alles gleich behandelt ;)

Deshalb immer spezifische Exceptions schmeißen. Dann macht das Fehlerhandling auch "Spaß" und es tut wie es soll ;)