Entwickler-Ecke
WinForms - Thread mehrere Aufgaben übergeben
m.keller - Do 30.01.14 10:29
Titel: Thread mehrere Aufgaben übergeben
Hallo,
nun habe ich mich mit Threads beschäftigt.
Folgendes Problem:
Es besteht eine Form-Anwendung die über eine Datenbank gesteuert wird. Es werden Werte ausgewertet und demnach Methoden aufgerufen, dieser Aufruf geschieht zur zeit mit einem Timer.
Da einige Methoden sehr aufwändig sind, friert die Form-Ansicht ca. 1 min ein.
Um dieses zu umgehen, hatte ich die einzelnen Methoden in Threads gepackt.
Nun müssen diese aber teilweise nach einander ausgeführt werden, da sonst werte für die nächste Methode fehlen, die aus der Datenbank kommen und mit der vorigen Methode in die Datenbank eingetragen worden sind.
Jetzt habe ich etwas gesucht und folgende Aussage gefunden
| Zitat: |
starte einen Thread und lass ihn die ganze Zeit laufen. Schick ihm seine Arbeitsaufträge über eine synchronisierte Queue.
|
Ich verstehe darunter jetzt, dass ich dem Laufenden Thread neue Aufträge (Methoden die er abarbeiten soll) übergeben kann.
Aber wie mache ich das am sinnvollsten?
Danke schon mal
Ralf Jansen - Do 30.01.14 11:07
Es gibt viele Wege mit Threads zu arbeiten um dich da abzuholen wo du stehst und was passendes zu deinem Ansatz vorzuschlagen solltest du uns zeigen was du hast.
Christian S. - Do 30.01.14 11:14
Hallo!
Asynchrone Programmierung würde ich nur noch in Ausnahmefällen "von Hand" mit der Thread-Klasse machen, sondern mich auf die Funktionen verlassen, die das Framework mit der Task-Klasse und async / await. Das ist hier ganz gut erklärt:
http://msdn.microsoft.com/de-de/library/hh191443.aspx#BKMK_AsyncandAwait
Der Vorteil ist, dass Du zeitaufwendige Aufgaben in Threads abarbeiten kannst, während Dein UI ansprechbar bleibt, der Programmfluss aus Sicht des Programmierers aber im wesentlichen der selbe bleibt wie bei einem Programm, welches keine Threads verwendet. Beispiel:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| private async void button1_Click(object sender, EventArgs e) { var t = Task.Run<int>((() => { for (int i = 0; i < 10; i++) Thread.Sleep(1000); return 42; }));
textBox1.Text = "Ich tue was ...";
textBox1.Text = (await t).ToString(); } |
Hier erstelle ich einen Task, der 10 Sekunden braucht, um fertig zu werden. Während der im Hintergrund läuft, bleibt die UI ansprechbar und z.B. wird die Textbox aktualisiert. Erst wenn ich explizit auf das Ergebnis des Tasks warte, wird der Programmfluss unterbrochen. Aber auch da friert die UI nicht ein, sondern die Kontrolle über das Programm wird zwischenzeitlich an die aufrufende "Stelle" zurückgegeben, was in diesem Fall im UI-Thread ist.
Nutzt man diese Funktionen, muss man gar keine Warteschlangen o.ä. erstellen, sondern kann sich "ums Wesentliche" kümmern :-)
Viele Grüße
Christian
m.keller - Do 30.01.14 11:32
Danke.
Hier kurz ein Code wie es bei mir gerade aussieht.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| private void Form1_Load(object sender, EventArgs e) { Timer t1 = new Timer(); t1.Interval = 500; t1.Tick += new EventHandler(t1_Tick); t1.Start();
}
private void t1_Tick(object sender, EventArgs e) { client_automatic(); }
private void client_automatic()
switch (auswahl) { case 0: if (initialized == true) { new System.Threading.Thread(new System.Threading.ThreadStart(SQL_WriteNewData)).Start(); } break; default: break; } |
Dies soll nur als Beispiel dienen in switch sind noch einige weitere aufrufe.
Nun muss ich nach dem der Thread beendet ist einen wert in die SQL Datenbank schreiben um zu wissen das diese Methode auch wirklich ausgeführt worden ist.
Da dies so zu aufwändig ist, dachte ich "client_automatik" in einem Thread laufen zu lassen.
Aber anscheinend gibt es hier sehr unterschiedliche Meinungen welche Vorgehensweise am sinnvollsten ist.
Oder ich habe mich falsch ausgedrückt.
Ralf Jansen - Do 30.01.14 12:27
Gibt halt n Vorgehensweisen und es sind nicht n weil sich die Entwickler nicht einigen konnten sondern es eben je nach Anwendungsfall einen anderen geeigneten gibt.
Denn relevanten Teil hast du leider weggelassen ;) Du sprachst von mehreren Aufgaben die voneinander abhängen und du in irgendeiner Reihenfolge nacheinander ausführen möchtest.
Bei dem Teil lässt sich dir immer noch nicht konkret weiterhelfen weil wir nicht wissen was das für Dinge sind und wie die zusammenhängen. Es gibt da wieder dutzende Möglichkeiten das zu machen von Queues, Thread Joins, awaits, Continuations oder weil eh alles nacheinander passieren muß gleich auf Threads zu verzichten.
Da du scheinbar noch nicht auf viel Code hockst der sich um Threads dreht würde ich sagen beschäftige dich mit dem von Christian verlinkten Verfahren (wenn dir .Net 4.5 zur Verfügung steht). Da sind die Optionen am größten.
m.keller - Do 30.01.14 12:38
Die voneinander abhängigen Methoden sind in der "clinet_automatik" Methode enthalten(20 Auswahlmöglichkeiten) .
jegliche Methode greift auf eine Datenbank zurück.
Da ich z.b. in einigen Methoden werte zurückerwarte und diese in die Datenbank schreibe, aber in einer anderen Methode genau diese Rückgabewerte auslesen muss, dürfen diese zwei Methoden unter keinen Umständen zusammen abgearbeitet werden.
D.h. es muss in irgend einer weise sicher gestellt werden, dass ich erst wenn Methode 1. aufgerufen wird und dann Methode 3. angefordert wird erst Methode 1. beendet sein muss um mit 3. weiter zu machen.
Ich glaube ich kann das gerade sehr schlecht erklären. Tut mir leid.
Ich hoff das es jetzt etwas deutlicher geworden ist.
leider sitze ich noch auf .Net 3.5 :-(
Ralf Jansen - Do 30.01.14 12:58
| m.keller hat folgendes geschrieben: |
| D.h. es muss in irgend einer weise sicher gestellt werden, dass ich erst wenn Methode 1. aufgerufen wird und dann Methode 3. angefordert wird erst Methode 1. beendet sein muss um mit 3. weiter zu machen. |
Und wenn Methode 1 noch nie gelaufen ist und auch gerade nicht läuft? Was soll dann Methode 3 machen? Methode1 anwerfen und warten?
Moderiert von
Th69: Beitragsformatierung überarbeitet: Quotes richtig gesetzt
m.keller - Do 30.01.14 13:05
Nein.
Die abfolge wird von woanders über die Datenbank gesteuert (von extern).
Ich muss lediglich dafür sorgen, dass keiner von diesen Methoden Parallel laufen, und das die Form nicht einfriert.
Am besten wäre das die Methode "client_automatik" in einem Thread oder so etwas läuft.
Wenn diese Methode durchlaufen ist, wüsste ich, dass nur maximal eine Methode in switch ausgeführt worden ist.
Es wär aber nicht sinn der Sache, nach jedem tick von meinem Timer einen neuen Thread zu erstellen.
Somit müsste ich in diesem falle wissen ob der Thread wieder beendet worden ist um ihn wieder neu zu starten.
Falls das möglich ist.
Ralf Jansen - Do 30.01.14 16:54
Dann würde ich die ganze Logik die da in client_automatik passiert in einen Thread auslagern und diesen dann die Methoden nacheinander ausführen lassen. Wenn die eh immer nacheinander ausgeführt werden sollen bringt es nichts die wiederum in einzelnen Threads auszuspalten nur im die danach wieder zu sequenzialisieren.
m.keller - Do 30.01.14 16:57
was passiert den wenn ich den Thread "client_automatic" mit dem tick immer wieder erstelle?
Wird der durchlaufene Thread gelöscht, oder existiert dieser noch?
Ansonsten könnte ich das neue erstellen des Threads solange mit einem Bit sperren bis der Thread durchlaufen ist.
Ralf Jansen - Do 30.01.14 17:09
Merk dir einfach die Thread Instanz beim starten des Threads. Die hat eine IsActive (oder so) IsAlive Property die du bei jedem Timer Tick abfragen kannst.
m.keller - Do 30.01.14 17:13
Ich hatte es gerade mal auf diese weise versucht.
C#-Quelltext
1: 2: 3: 4: 5: 6:
| if (autoDisabled == false) { autoDisabled = true; System.Threading.Thread test = new System.Threading.Thread(client_automatic); test.Start(); } |
"autoDisabled" wird am ende der Methode "client_autoomatic()" wieder auf false gesetzt.
schön ist das glaube ich nicht.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!