Laden...

sequenzielles Threading von Methodenzugriffen

Erstellt von oskar27 vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.230 Views
O
oskar27 Themenstarter:in
12 Beiträge seit 2018
vor 5 Jahren
sequenzielles Threading von Methodenzugriffen

Hallo liebe Community,

ich bin neu im Forum und würde mich über einen Tipp freuen, der mir in folgender Problemstellung weiter helfen kann: Ich nutze einen Backgroundworker der per Timer Daten abruft. Wunderbar soweit. Bei Auftreten bestimmter Daten soll ein Datenbankeintrag erfolgen. Das Auftreten von neuen Daten erfolgt z.T. schneller als der DBInsert. Es muss sicher gestellt werden, dass immer ein DBInsert erfolgt. Also nix "verloren" geht bzw. wegen Fehlzugriff ("Meldung Zugriff auf geschützten Speicher...") nicht erfolgt. Es können maximal 20 "gleichzeitige" Zugriffe sein, die geregelt werden müssten.
Ich habe mir dazu die SyncQueue >> von #herbivore angesehen, die möglicherweise passt, allerdings die Schleife des WorkerThreads passt bei mir nicht ins Konzept. Die Aufrufe "DBInsert" müssten sich in die Queue einfügen und direkt selbst dequeuen, bis alle Inserted sind.
Welches Konzept wäre für diesen Fall das beste? Habe es ebenfalls mit Threadpool und Autoreset probiert. Aber hier wohl nicht korrekt umgesetzt. Es gab auch hierbei die Exception "Zugriff auf geschützten Speicher...".
Also in einem Satz, die DBInserts sollen parallel zum BackgroundworkerThread sequentiell abgearbeitet werden können, ohne sich zu behindern oder verloren zu gehen.
Edit: Was die Vielfalt an Möglichkeiten etwas einschränkt ist: Targeting auf .Net Framework 2.0.
Vielen Dank im voraus.

Beste Grüße
Oskar

49.485 Beiträge seit 2005
vor 5 Jahren

Hallo oskar27,

Das Auftreten von neuen Daten erfolgt z.T. schneller als der DBInsert. Es muss sicher gestellt werden, dass immer ein DBInsert erfolgt.

ich würd sagen, das kann gar nicht sichergestellt werden. Denn solange bis das DBInsert durch ist, liegen die Daten nur im Hauptspeicher und der ist flüchtig. Wenn also der Rechner in so einem Moment abstürzt, warum auch immer, sind die Daten einfach futsch.

Es können maximal 20 "gleichzeitige" Zugriffe sein, die geregelt werden müssten.

Was spricht dann gegen 20 Worker Threads? Dann hast du doch eigentlich genau, was du willst. Möglich ist das, wie ich schrieb:

Mehrere Worker-Threads können sich bei Bedarf eine SyncQueue <T> teilen. Es dürfen also gleichzeitig beliebig viele Threads Elemente in die Queue einstellen und/oder Elemente aus der Queue herausholen.

Die Aufrufe "DBInsert" müssten sich in die Queue einfügen und direkt selbst dequeuen, bis alle Inserted sind.

Naja, reinschreiben in die Queue würde doch dein BackgroundWorker/Timer. Und rausholen würden die Worker, die die DBInserts ausführen. In dem Moment, wo das zu einem Eintrag gehörige DBInsert startet/läuft, ist der Eintrag schon aus der Queue raus.

Die Queue dient ja gerade dazu, einen Eintrag synchronisiert vom Auftraggeber (Producer) an den bzw. einen Worker-Thread (Consumer) zu übergeben. Die eigentliche Verarbeitung erfolgt immer erst nach der Übergabe (also nach dem Dequeue).

Im Idealfall ist die Queue also (quasi) immer leer, nämlich wenn für jeden Eintrag immer gleich ein Worker bereit steht, also verfügbar ist. Füllen tut sich die Queue nur, wenn (temporär) mehr Aufträge eingehen, als (gerade) verarbeitet werden können.

Hilft dir das?

herbivore

O
oskar27 Themenstarter:in
12 Beiträge seit 2018
vor 5 Jahren

Hallo herbivore, vielen Dank für Deine Ausführung! Da ich momentan nur einen BW habe, der die Daten getimed ausliest und ggf. einen DBInsert anstößt, muss also z.B. ein zweiter getimeter BW dauerhaft mit dem Dequeing beschäftigt werden? Kollisionen irgendeiner Art mit dem Queuing sind da nicht zu erwarten?
Gibt es ev. noch eine weitere Möglichkeit, ähnlich dem ThreadPool, nur eben sequentiell, wo ich ohne zusätzliches Dequeuing auskomme? (.Net 2.0 ...)
VG

49.485 Beiträge seit 2005
vor 5 Jahren

Hallo oskar27,

Da ich momentan nur einen BW habe, der die Daten getimed ausliest und ggf. einen DBInsert anstößt, muss also z.B. ein zweiter getimeter BW dauerhaft mit dem Dequeing beschäftigt werden?

schöner wäre natürlich, wenn du bei neuen Daten eine unmittelbare Benachrichtigung kriegen würdest, z.B. von dem Prozess oder Thread, der die Daten schreibt. Im Idealfall würde also der eigentliche Producer der Daten auch das Enqueue durchführen. Wenn das nicht möglich ist, ist Polling (also dein getimeter BGW) auch ok.

Grundsätzlich könnte dein getimeter BGW auch die DBInserts ausführen. Es ist nicht zwangsläufig erforderlich, das in einem anderen, weiteren Thread/BGW zu machen.

Es kommt halt darauf an, was wie lange dauert. Wenn die DBInserts viel länger dauern als das Intervall deines BGW, dann wäre es schon ratsam, mindestens einen weiteren Thread zu verwenden. Es können aber wie gesagt auch viel mehr weitere Threads sein, nämlich wenn du mehrere DBINserts gleichzeitig anstoßen/ausführen willst.

Kollisionen irgendeiner Art mit dem Queuing sind da nicht zu erwarten?

Also die SyncQueue ist ja gerade dafür da, um Kollisionen zu vermeiden. Wenn der Producer die Arbeitsaufträge einstellt und sie danach nicht mehr anfasst und wenn der/die Consumer die Arbeitsaufträge erst anfassen, nachdem sie sie rausgeholt haben, dann gibt es bezüglich der Arbeitsaufträge schon mal keine Kollisionen. Wenn es weitere gemeinsame Daten gibt, muss der Zugriff von Producer und Consumer auf diese natürlich synchronisiert erfolgen, damit es keine Kollisionen gibt. Das steht aber so auch schon in der Beschreibung der SyncQueue.

Gibt es ev. noch eine weitere Möglichkeit, ähnlich dem ThreadPool, nur eben sequentiell, wo ich ohne zusätzliches Dequeuing auskomme? (.Net 2.0 ...)

Wie schon oben geschrieben: Grundsätzlich könnte auch alles in einem Thread/BGW laufen. Wirklich zwingend ist ein zweiter Thread nur, wenn der erste Thread der GUI-Thread wäre (siehe [FAQ] Warum blockiert mein GUI?), aber ist es ja bei dir nicht. Bei dir kommt es wie gesagt nur darauf an, wie lange was dauert und ob du mehrere DBInserts parallel ausführen möchtest.

herbivore