2009-03-06 7 views
5

Eine weitere Synchronisationsfrage ... Ich hoffe euch wird es nicht genervt;)Synchronisation für mehrere Leser, Einzelschreiber?

Angenommen, das folgende Szenario: eine zentrale Datenstruktur (sehr groß, also möchte ich es nicht wirklich unveränderlich machen und es kopieren Ich möchte sogar nicht mehrere Kopien im Speicher behalten), mehrere Leser-Threads, die schreibgeschützt auf diese Datenstruktur zugreifen, und einen Writer-Thread, der die Datenstruktur im Hintergrund auf dem neuesten Stand hält.

Ich synchronisiere derzeit alle Zugriffe auf die Datenstruktur, was gut funktioniert (keine Synchronisationseffekte, keine Deadlocks). Was ich an diesem Ansatz nicht mag, ist, dass ich meistens eine Menge Leser-Threads aktiv habe und der Writer-Thread nur ab und zu aktiv ist. Jetzt ist es völlig unnötig, dass die Leser-Threads darauf warten, dass andere Leser-Threads beendet werden. Sie könnten leicht parallel auf die Datenstruktur zugreifen, solange der Autorenthread gerade nicht schreibt.

Gibt es einen schönen und eleganten Weg, um diese Art von Szenario zu lösen?

EDIT: Vielen Dank für die Antworten und Links! Lassen Sie mich nur eine weitere kurze und verwandte Frage hinzufügen: Wenn der in den kritischen Abschnitten des Lesers ausgeführte Code nur eine sehr kurze Zeit benötigt (wie nur eine Hashtabellen-Suche), ist es sogar sinnvoll, eine der beschriebenen Techniken zu implementieren oder die Serialisierung Wirkung der Schlösser in diesem Fall nicht so schlecht? Skalierbarkeit und Leistung sind sehr wichtig. Was denken Sie?

BEARBEITEN 2: Ich habe gerade in eine Implementierung eines einzelnen Writer/multiple Leser - Sperre untersucht und diese Implementierung verwendet einen Monitor, um einige Code in der WaitToRead-Methode zu synchronisieren. Führt das nicht zu dem gleichen Serialisierungseffekt, den ich in erster Linie vermeiden wollte? (Immer vorausgesetzt, dass der zu synchronisierende Code kurz und schnell ist)

Antwort

9

eine Klasse gibt zu diesem Zweck in RTL (sysutils): TMultiReadExclusiveWriteSynchroniser

Es ist sehr einfach zu bedienen ist. Sie müssen Ihre Threads nicht streng wie Leser oder Schreiber kategorisieren. Rufen Sie einfach "BeginRead" oder "BeginWrite" in einem Thread auf, um eine Thread-sichere Operation zu starten. Rufen Sie "EndRead" oder "EndWrite" auf, um den Vorgang abzuschließen.

+0

Beachten Sie, dass diese Klasse in einigen Delphi-Versionen fatal beschädigt ist. Es ist seit Delphi 2005 behoben, vielleicht früher. –

1

Immer wenn der Autor zugreifen möchte, reiht man eingehende Leser ein (warten auf Bedingung), warten, bis die aktiven Leser fertig sind, schreiben und wenn fertig eingereihte Leser Zugriff.

2

Die Verwendung eines Reader-Writer-Schlosses löst das Problem. Mehrere Leser können auf eine Datenbank zugreifen, und ein Schreiber erhält eine Sperre, sobald alle Leser gelesen haben.

Dies kann jedoch dazu führen, dass der Schreiber niemals Zugriff auf die Quelle hat, da immer neue Leser Zugriff haben. Dies kann gelöst werden, indem neue Leser blockiert werden, wenn ein Schreiber Zugriff möchte: Der Schreiber hat eine größere Priorität. Der Schreiber erhält Zugang, sobald alle Leser der Quelle gelesen haben.

0

Das Leser-Schreiber-Schloss ist, was Sie brauchen. Tutorial hat eine Beschreibung, aber ich bin sicher, dass jemand dies als Standard zu Delphi hinzugefügt hat. Kann es wert sein zu überprüfen D2009 hat es noch nicht.

1

Niemand kann wirklich Ihre Frage beantworten, ob die Serialisierung die Leistung in Ihrer Anwendung stark beeinflusst - Sie müssen dies für sich selbst profilieren, und die Ergebnisse hängen stark von der Anzahl der Threads, Kerne und der spezifischen Auslastung ab.

Beachten Sie jedoch, dass die Verwendung einer clevereren Synchronisierung als kritische Abschnitte, wie z. B. das Reader-Writer-Lock, Probleme mit sich bringen kann, die schwer zu debuggen und zu beheben sind. Sie müssen wirklich genau hinsehen, ob der erhöhte Durchsatz die potenziellen Probleme überwiegt. Beachten Sie auch, dass der Durchsatz möglicherweise nicht erhöht wird, insbesondere wenn der gesperrte Code sehr kurz und schnell ist. Es gibt eine nice article by Jeffrey Richter, die tatsächlich dieses Zitat enthält:

Leistung Selbst wenn es keine Konkurrenz für eine ReaderWriterLock ist, seine Leistung ist sehr langsam. Beispielsweise dauert ein Aufruf der AcquireReaderLock-Methode etwa fünfmal länger als ein Aufruf der Enter-Methode von Monitor.

Dies ist für .NET natürlich, aber die zugrunde liegenden Prinzipien gelten auch.

+0

Jeffrey Richter spricht über die Implementierung eines ReaderWriterLock in der .NET-Bibliothek. Er selbst stellt im selben Artikel eine effiziente Implementierung eines solchen Schlosses vor. Aber danke! Ich hatte Angst, dass es keine klare Antwort geben wird;) – jpfollenius

+1

@Smasher: In der Tat. Es gab jedoch Probleme mit der MREW-Implementierung in der VCL, und die Leute trauten ihm nicht wirklich. Jeffrey Richter macht das seit über 15 Jahren, ich würde seinem Urteil und seinen Implementierungen vertrauen. Versuchen Sie einfach, darüber informiert zu werden, worauf Sie sich einlassen. – mghie