C# Threading-Warteschleife
lima-city → Forum → Programmiersprachen → Programmieren mit .NET & Mono
array
aufgabe
bestimmen
code
datei
datenbank
erledigen
legen
null
problem
programm
queue
sagen
schleife
set
starten
string
system
tun
warteschlange
-
Ich google nun schon eine Weile nach einer Lösung für mein Problem, aber leider wird immer davon ausgegangen, dass man nicht ein und den selben Thread erneut aufruft, sondern mehrere parallel laufen.
Folgende Ausgangssituation:
Ich lasse für bestimmte Schreibvorgänge in eine Datenbank einen Thread erstellen, damit die GUI für den Benutzer nicht blockiert wird.
Dieser Thread hat nun nichts weiter zu tun, als alle Datensätze (nicht unerhebliche Menge) in die Datenbank zu übertragen, was einige Zeit beansprucht.
Während diesem Schreibvorgang ist die Datenbank-Datei schreibgeschützt und erlaubt keine weiteren Schreibvorgänge.
Mein Problem ist nun aber, dass dieser Thread durch einen FileSystemWatcher gestartet wird, der bestimmte Ordner auf neu erstellte Dateien prüft.
Werden diese Dateien zu schnell hintereinander erstellt, versucht das Programm einen neuen Thread zu starten, während der alte noch läuft.
Durch den Schreibschutz auf die Datenbankdatei crasht nun natürlich das Programm.
Da die asynchrone Ausführung hier durch den Schreibschutz nicht möglich ist, ich gleichzeitig aber auch keine Daten verlieren möchte, indem ich die Ausführung eines neuen Threads einfach ignoriere, während der alte noch läuft, müsste hier eine Warteschlange her, die ein und denselben Thread mit unterschiedlichen Dateien hintereinander abarbeitet.
Ich bräuchte also eine Art Thread-Array, in das ich noch Threads anfügen kann, während es bereits abgearbeitet wird.
Mein Pseudo-Code sieht derzeit in etwa so aus:
Thread thread; FileSystemWatcherEvent() { thread = new Thread(schreibFunktion); } private void schreibFunktion() { // Schreibe Datei in Datenbank, die das Event ausgelöst hat }
Ich hätte hierzu zwar schon was zu den Themen "Background Worker" und "Threadpool" gefunden, dort wird aber davon ausgegangen, dass man unterschiedliche Threads in die Warteschleifen hängt, um sie abzuarbeiten, nicht unterschiedliche Instanzen des selben Threads.
Kann man ein und denselben Thread mehrmals hintereinander in eine Warteschlange hängen?
Bzw. kann ich dieses Problem anders lösen?
Also quasi:
ThreadQueue queue = new ThreadQueue[3]; queue[thread]; queue[thread]; queue[thread]; oder ähnlich....
Ich hoffe, es ist verständlich, was ich meine. -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage
-
Also, ich würde versuchen, den gleichen Thread schon 15 mal zu starten, aber mit einer Mutex zu versehen. Bedeutet: Thread wird gestartet -> Mutex schließen im Thread. Abarbeiten, Mutex öffnen, Thread zu Ende.
Da ich nur mit Qt arbeite kann ich nicht sagen, ob soetwas auch in C# oder .NET zur Verfügung steht, allerdings glaube ich schon.
Also Stichwort: Mutex
Liebe Grüße -
Habe mir jetzt mal die Methoden zum Mutex angesehen, ich finde da aber nur Funktionen, um zu warten, bis die Ausführung eines Threads beendet ist, bevor mit dem nächsten begonnen wird.
Die Reihenfolge muss ich demnach aber selbst bestimmen, bevor mit der Ausführung begonnen wird.
Ich sehe da keine Möglichkeit, an den Mutex Threads zu übergeben, während dieser bereits abgearbeitet wird.
Muss aber zugeben, dass ich noch keine Mutex benutzt habe und auch gar nicht weiß, was die genau machen sollen.
Als Beschreibung steht nur, es wäre ein Synchronisierungstyp.
Vielleicht kannst Du mir ein Code-Beispiel geben?
Ich hätte inzwischen schon eine Möglichkeit gefunden, die funktionieren könnte.
Dabei wird aber ein Array an Threads während der Ausführung der foreach-Schleife mit neuen Threads bestückt, was dann eine Exception auslöst.
Die Exception fange ich ab, lösche alle Einträge bis zu dieser Exception, und starte die foreach-Schleife mit den verbleibenden (während der Ausführung hinzugefügten) Threads neu.
Das ist aber eine unschöne Lösung, weil hier gezielt von einem Fehler ausgegangen werden muss.
Beitrag zuletzt geändert: 11.6.2012 17:40:11 von adelwoehrer -
Hallo adelwoehrer,
an Deiner Stelle würde ich nur mit eine Thread arbeiten. Den Thread würde ich solange schlafen legen, bis es etwas zu tun gibt und die zu erledigenden Aufgaben würde ich in einem Queue speichern.
Hier mal etwas Beispielcode:
using System; using System.Collections.Generic; using System.Threading; namespace SimpleWorker { class BackgroundTask { public Int32 Foo{get;set;} public String Bar{get;set;} public BackgroundTask(Int32 foo, String bar) { Foo = foo; Bar = bar; } } class Worker { private Queue<BackgroundTask> tasks; private AutoResetEvent evtStart; private AutoResetEvent evtExit; private Thread thread; private void executeTasks() { while(true) { if(WaitHandle.WaitAny(new WaitHandle[] {evtStart, evtExit}) == 0) { BackgroundTask tsk; while(true) { lock(tasks) { if(tasks.Count > 0) tsk = tasks.Dequeue(); else tsk = null; } if(tsk == null) { break; } else { Console.WriteLine(tsk.Foo + " " + tsk.Bar); Thread.Sleep(1000); } } } else { return; } } } public Worker() { tasks = new Queue<BackgroundTask>(); evtStart = new AutoResetEvent(false); evtExit = new AutoResetEvent(false); } public void AddTask(BackgroundTask bt) { if(thread == null) { thread = new Thread(executeTasks); thread.Start(); } lock(tasks) { tasks.Enqueue(bt); evtStart.Set(); } } public void Stop() { evtExit.Set(); thread.Join(); thread = null; tasks.Clear(); } } class Program { public static void Main(string[] args) { Worker wrk = new Worker(); wrk.AddTask(new BackgroundTask(1, "Eins")); wrk.AddTask(new BackgroundTask(2, "Zwei")); Thread.Sleep(500); wrk.AddTask(new BackgroundTask(3, "Drei")); wrk.AddTask(new BackgroundTask(4, "Vier")); Thread.Sleep(6000); wrk.AddTask(new BackgroundTask(5, "Fünf")); wrk.AddTask(new BackgroundTask(6, "Sechs")); Thread.Sleep(500); wrk.AddTask(new BackgroundTask(7, "Sieben")); wrk.AddTask(new BackgroundTask(8, "Acht")); Thread.Sleep(300); wrk.Stop(); Console.ReadKey(); } } }
Die Klasse BackgroundTask ist hier nur ein Dummy. Diese muss alle Informationen beinhalten, die der Worker-Thread zum erledigen der Aufgabe benötigt.
Die Klasse Worker kapselt den Thread ein. Mit Hilfe des Events 'evtStart' wird der Thread aufgeweckt um Tasks abzuarbeiten. Das Event 'evtExit' wird verwendet um dem Thread zu sagen, dass er sich beenden soll.
Damit es keinen Konflikt beim Lesen und Schreiben gibt wird der Queue beim Ändern einfach mit 'lock()' gesperrt. -
Funktioniert grandios.
Vielen Dank.
Beitrag zuletzt geändert: 11.6.2012 22:18:48 von adelwoehrer -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage