AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte Workerthread: Der Diener im Hintergrund
Thema durchsuchen
Ansicht
Themen-Optionen

Workerthread: Der Diener im Hintergrund

Ein Thema von alzaimar · begonnen am 12. Jun 2007 · letzter Beitrag vom 23. Jun 2011
Antwort Antwort
Seite 5 von 8   « Erste     345 67     Letzte »    
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, 1177x aufgerufen)
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
 
alzaimar

 
Delphi 2007 Enterprise
 
#41
  Alt 18. Jun 2007, 08:16
Sag mal, dein 'P4 HT' hat Hyperthreading? Hmmm. Dann gibt es vermutlich irgendwo einen Konflikt, bzw. einen Deadlock, der bei Einprozessorsystemen nicht auftritt.

Zitat von kalmi01:
... und ich möchte mal behaupten, das die Version (subjektiv) langsamer ist als der Vorgänger.
Was ist langsamer? Da wird doch nicht viel gemacht?

Funktioniert denn der 'Terminate' Button? Kannst Du danach weiter testen oder hängt dann die SW wieder? Der Terminate-Button ruft 'Free' auf und instantiiert den Pool anschließend neu.

Was siehst Du eigentlich im Memo, wenn Du die Anwendung beendest?
  Mit Zitat antworten Zitat
kalmi01
 
#42
  Alt 18. Jun 2007, 12:36
Zitat:
Was ist langsamer? Da wird doch nicht viel gemacht?
Das ist mir wohl klar.
Auf dem einen PC rasen die Threads einfach nur so durch (Uni-Proz).
Auf dem anderen dauert es ca. 1 Sek. pro Thread.
Der Effekt tritt auch nur in der Pool-Variante auf.

Wenn ich das Prog aus der IDE starte, dauert es fast 2 Minuten, bis es mit der Initialisierung fertig ist.

Der normale Worker funktioniert auf beiden Systemen sauber !

Zitat:
Funktioniert denn der 'Terminate' Button?
Ja

Zitat:
Was siehst Du eigentlich im Memo, wenn Du die Anwendung beendest?
Was soll ich denn sehen ?
Bei einer Anwendung die hängt, passiert halt nicht viel.

Es gibt seltsamer Weise auch keinen Log von Eurekalog.

Laut Taskmanager liegt WorkerThreadPoolDemo auch nur gelangweilt in der Gegend rum.
  Mit Zitat antworten Zitat
alzaimar

 
Delphi 2007 Enterprise
 
#43
  Alt 18. Jun 2007, 14:54
Hi kalmi01,

Schön, das Du Dir die Zeit nimmst.

Ich erwarte bei der Pool-Demo, das alle 500 ms die Threads quasi gleichzeitig den nächsten Job ausführen. Denn der Job besteht ja nur aus einem 'Sleep(500)' und 'Log ins Memo'.

Wenn das auf dem HT-PC anders abläuft, dann wundert mich das (ich würde sogar postulieren, das Du ein anderes Programm ausführst )

Was die Ausgabe anbelangt, bezog ich mich auf das Testprog, das ich Dir per PN zugeschickt habe.

Eine neue Version mit Testausgaben (per Kompilerdirektive abschaltbar) ist im 1.Post
  Mit Zitat antworten Zitat
kalmi01
 
#44
  Alt 18. Jun 2007, 15:32
Zitat von alzaimar:
Wenn das auf dem HT-PC anders abläuft, dann wundert mich das (ich würde sogar postulieren, das Du ein anderes Programm ausführst
Da könntest Du nicht ganz unrecht haben
Mit dem neuen Source von Dir funktioniert es einwandfrei

Der neu eingestellt Source hat 24 Unterschiede in der csWorkerThreadPool.pas, gegenüber dem per PN geschickten.
  Mit Zitat antworten Zitat
alzaimar

 
Delphi 2007 Enterprise
 
#45
  Alt 18. Jun 2007, 17:45
Na, Schlamperei meinerseits (und wie gesagt: Da war noch so eine Kleinigkeit )


Also, heute abend mach ich den Code nochmal sauber, kommentiere es noch ausführlich (wenn mir noch etwas einfällt) und stell eine überarbeitete Version hier ein.

Danke für die Geduld und die Tipps!
  Mit Zitat antworten Zitat
Benutzerbild von x000x
x000x

 
Delphi XE2 Professional
 
#46
  Alt 19. Jun 2007, 01:18
Moin moin,

ich denke ich habe noch eine Kleinigkeit gefunden?!
Sollte es jetzt nicht in TWorkerThreadPool einen Setter für fOnJobException
geben? Also ähnlich wie SetOnAction...

Dann hab ich noch ne Frage:
Angenommen, ich habe verschiedene Jobs die DB-Abfragen o.ä. erledigen.
Nach meinem Verständnis muss ich in jedem Job die TADOConnection erstellen.
Hab ich das jetzt richtig verstanden oder langt es, wenn ich Sie einmal
in z.B. einem Datenmodul einzufüge? (Wenn ja, dann hätte ich dafür gerne eine Erklärung)
Peter
  Mit Zitat antworten Zitat
alzaimar

 
Delphi 2007 Enterprise
 
#47
  Alt 19. Jun 2007, 08:05
Hi x000x,

Super! Da fehlte wirklich der Setter, der das Event an die einzelnen Threads weiterleitet... ist eingebaut.

ADO verwendet COM, und COM ist nicht ohne Weiteres threadübergreifend. Die Interfaces sind nur im Thread gültig. Willst Du sie einem anderen Thread zur Vergfügung stellen, musst Du sie über den Marshaller übergeben (ab in einen Stream, raus aus einem Stream). Irgendwie so.

ADO verwaltet jedoch einen Connection-Pool, der das vermutlich alles regelt.

Denk dran: TMyJob.UsesCOMObjects muss bei Verwendung von ADO auf True gesetzt werden, damit CoInitialize aufgerufen wird.
  Mit Zitat antworten Zitat
kalmi01
 
#48
  Alt 19. Jun 2007, 08:11
Moin moin,
Zitat von alzaimer:
Da fehlte wirklich der Setter, der das Event an die einzelnen Threads weiterleitet... ist eingebaut.
Du lügst ja
Ich hätte da mal einen Vorschlag: Schreib doch beim Download in den Kommentar, von wann die Version ist

Edit: Uuund ? Wo bleibt die Korrektur ?
  Mit Zitat antworten Zitat
alzaimar

 
Delphi 2007 Enterprise
 
#49
  Alt 19. Jun 2007, 09:02
Zitat von kalmi01:
Ich hätte da mal einen Vorschlag: Schreib doch beim Download in den Kommentar, von wann die Version ist
Das würde ein Mindestmaß an Planung und Ordnung bedeuten. Das liegt außerhalb meiner Möglichkeiten.
  Mit Zitat antworten Zitat
kalmi01
 
#50
  Alt 19. Jun 2007, 10:03
Zitat von alzaimar:
Zitat von kalmi01:
Ich hätte da mal einen Vorschlag: Schreib doch beim Download in den Kommentar, von wann die Version ist
Das würde ein Mindestmaß an Planung und Ordnung bedeuten. Das liegt außerhalb meiner Möglichkeiten.
Das Genie beherrscht das Chaos
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 5 von 8   « Erste     345 67     Letzte »    


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:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:15 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz