AGB  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte Workerthread: Der Diener im Hintergrund

Workerthread: Der Diener im Hintergrund

Ein Thema von alzaimar · begonnen am 12. Jun 2007 · letzter Beitrag vom 23. Jun 2011
Antwort Antwort
Seite 8 von 8   « Erste     678
alzaimar
Registriert seit: 6. Mai 2005
Hallo,

Threads sind eine tolle Sache. Wenn man sie versteht. Wenn nicht, bringen sie einen an den Rand des Wahnsinns. Oder ein Stück weiter. Ich weiss, wovon ich rede.

Ich benötige für meine Applikationen immer mal wieder einen Thread, der ab und zu einzelne Jobs im Hintergrund ausführen muss. Wenn man z.B. auf bestimmte Ereignisse reagieren muss, diese Reaktion aber zeitaufwändig ist, dann kann die Ereignisbehandlung während der Ausführung des Eventhandlers blockiert sein.

Also habe ich einen generischen Thread implementiert, der einzelne Aufgaben (Jobs) im Hintergrund abarbeitet. Ich muss dazu nur den Job selbst definieren, alles Andere macht dieser Thread. Diese Threads nennen sich auch 'worker threads', weil sie eben ankommende Arbeiten ausführen.

So ein Job kann z.B. das Einlesen einer Tabelle von einer Datenbank sein, oder auch das Abspeichern von Daten.

Die Unit instantiiert einen Workerthread 'PendingJobs', den man sofort mit Arbeit befüllen kann. Dazu ruft man einfach die 'AddJob'-Methode auf:
Delphi-Quellcode:
...
PendingJob.AddJob (TMyJob.Create);
...
Die Anweisung schiebt den Job ans Ende der Jobliste und aktiviert ggf. den Thread (wenn der nicht sowieso schon aktiv ist). Der TMyJob wird dann 'demnächst' im Hintergrund ausgeführt.

Wenn man einen Job definiert, der mit COM-Objekten arbeitet (z.B. ADO) dann setzt man die Eigenschaft 'UsesCOMObjects' des Jobs auf True.


Der Thread verwendet eine Semaphore sowie eine Threadliste (die Liste der noch nicht ausgeführten Jobs). Auf Schnickschnack habe ich verzichtet, das kann jeder selbst einbauen.

Ich habe die Unit sowie eine kleine bescheuerte Demo bereitgestellt, die jedoch zeigt, wie einfach man Hintergrundarbeiten in seiner Anwendung implementieren kann.

Kritik, Verbesserungs- und Erweiterungsvorschläge sind ausdrücklich erwünscht.

Viel Spaß damit.

Update: Die Idee von thkerkmann wurde aufgenommen: Die Synchronize-Methode des Workerthreads ist nun public und kann innerhalb der TJob.Execute-Methode aufgrufen werden.

Update: Idee von shmia: Exception-Notification Event, und eine verbesserte Beendigung des Workerthreads. Man kann unn steuern, ob vor Beendigung alle ausstehenden Jobs noch abgearbeitet werden sollen oder nicht.

Update: Aus dem Thread wurde ein Threadpool (Idee von shmia). Er ist in einer wackeligen Version fertig. Er läuft in der Demo stabil, aber was heißt das schon. Ich würde Euch bitten, mal kräftig gegen die Klasse zu treten. Mal sehen, was sie aushält.

Der Threadpool verwaltet mehrere Threads (Anzahl einstellbar, auch zur Laufzeit), die gemeinsam die oben erwähnte Jobliste abarbeiten.

Update vom Threadpool: Schleifenvariablen als Cardinal deklariert, wenn Schleifenende = 'X-1', und X=0, bombt es.

Update vom Threadpool: Memoryleak beim Beenden beseitigt. Weiterhin stellt die Unit keine Instanz 'PendingJobs' mehr bereit. Denn das wurde im Finalisierungsabschnitt der Unit wieder freigegeben. Wenn die Classes-Unit ihren Finalisierungsabschnitt schon durchlaufen hat, gibt es Probleme.

Update vom Threadpool: Das Herabsetzen der Poolsize zur Laufzeit führte zu einem Speicherleck, ein fehlendes 'UnlockList' im der Clear-Methode der JobList und noch ein paar Kommentare.

Update vom Threadpool: x000x hat einen Bug gefunden: Die Setter-Methode des OnJobException-Events muss den Methodenzeiger natürlich an die einzelnen Threads weiterleiten. Weiterhin habe ich die Workerthread-Unit rausgenommen. Man braucht sie nicht mehr.

Update vom Threadpool: Die aktuelle Version läuft stabil, sie ist in einer Kundenanwendung im Einsatz.

Update vom Threadpool: Neue Methode, um aus einem Job heraus Nachrichten zu verschicken (siehe beiliegende Demo).

Update: Eigenschaft 'Terminated' des TWorkerThread wird publiziert, kleiner Fehler in der Clear-Methode beseitigt.

Update: Kleiner Hack, um den Threadnamen zu setzen (Debugginghilfe). Dank an Assertor.
Angehängte Dateien
Dateityp: rar workerthreadpool_198.rar (181,1 KB, 1098x aufgerufen)
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
 
alzaimar

 
Delphi 2007 Enterprise
 
#71
  Alt 26. Aug 2009, 19:12
Hi,

der Job wird dann natürlich im Hauptthread ausgeführt. Ich verwende das z.B. für Jobs, die meine Controls aktualisieren: Ein Job (der im Hintergrund läuft) erzeugt dann zum Schluss einen synchronisierten Job, der irgendwelche Aktualisierungen im Formular durchführt.

Um das Ende aller Jobs mitzubekommen, kannst Du doch zum Schluss einen 'Ende-Job' in die Queue einfügen. Wenn das nicht geht, würde ich pollen. Woher soll der Pool auch wissen, das alle Jobs abgearbeitet wurden?

Mit Hilfe der TWorkerThread.Notify-Methode kann ein Job eine synchronisierte Nachricht verschicken. Diese wird über das ThreadPool.OnNotify-Ereignis verschickt. Siehe Demo.
  Mit Zitat antworten Zitat
Viktorii
 
#72
  Alt 27. Aug 2009, 10:50
Moin zusammen.

Ich versuche gerade die Funktionsweise nachzuvollziehen und habe da ein paar Problem.

Ich hoffe die Frage ist jetzt nicht allzu blöd.

Wie kann die Execute Methode von TWorkerThread Parameter haben?

Execute wird ja nie direkt aufgerufen. Und trotzdem 'kennt' die Execute Methode aThread. Wie kann das also funktionieren?

Vielen Dank
  Mit Zitat antworten Zitat
alzaimar

 
Delphi 2007 Enterprise
 
#73
  Alt 27. Aug 2009, 10:59
Zitat von Viktorii:
Wie kann die Execute Methode von TWorkerThread Parameter haben?
Die Execute-Methode des Workerthreads hat keine Parameter, sondern nur der Job. Der Job ist einfach nur eine Klasse, um eine einzelne Aufgabe zu kapseln.
  Mit Zitat antworten Zitat
doctor-x
 
#74
  Alt 24. Mai 2011, 00:52
Hallo zusammen,

erst mal ein dickes Lob; TWorkerThreadPool finde ich eine echt klasse und einfach zu verwendende sache!

Habe dazu aber mal eine frage...

Wenn ich einen Job erstelle und starte, wie kann ich im Job auf ein schließen des Programms mit einem abbruch des Jobs reagieren ohne das ganze mit "Synchronized := True;" auszuführen?

Habe es mal mit "Synchronized := True;" und der abfage "Application.Terminated" gemacht, aber bei "Synchronized := False;" hab ich ja keinen sicheren zugriff auf den Main-Thread.

Habe ich irgenwie auf den Thread der meinen Job bearbeitet zugriff? (für die abfrage "Thread.Terminatd")

Danke schon mal im voraus!
Wolf
  Mit Zitat antworten Zitat
Thom

 
Delphi XE3 Professional
 
#75
  Alt 23. Jun 2011, 18:25
Hallo alzaimar,

Danke für die Arbeit!
Da die Units aber nicht mehr ganz taufrisch sind, werden in der inc-Datei Delphi 2010 und Delphi XE (noch) nicht berücksichtigt, so daß keine Benennung der Threads erfolgt. Das hat zwar keinen Einfluß auf die Arbeit des Pools - mir ist das nur beim Debuggen meines Programmes aufgefallen, daß da was fehlt...
Thomas Nitzschke
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:04 Uhr.
Powered by vBulletin® Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2017 by Daniel R. Wolf