In der folgenden Beispielklasse
%Vor% Viele Leser-Threads lesen das Values
-Array regelmäßig, während von Zeit zu Zeit ein einzelner Schreiber das gesamte Array durch den Setter mit einem neuen Wert ersetzt. Muss ich ReaderWriterLock
verwenden oder wird das von C # automatisch gehandhabt?
Edit: In meinem Fall ist die einzige erforderliche "Thread-Sicherheit": Nichts Schlechtes sollte passieren, wenn der Schreiber das Array ersetzt, während der Leser nach einem Wert sucht. Es ist mir egal, ob die Leser den neuen Wert sofort verwenden werden, solange sie ihn in Zukunft verwenden.
Diese Verwendung ist Thread-sicher:
%Vor%Diese Verwendung ist nicht threadsicher und kann zu Out-of-Bound-Ausnahmen führen:
%Vor%Ich würde es vorziehen, threadsichere Aufrufe natürlicher zu machen, indem ich so etwas tue:
%Vor%Natürlich können die Benutzer GetValues () in die Schleifen setzen, und das wäre genauso schlimm, aber zumindest ist es offensichtlich schlecht.
Je nach Situation kann eine noch bessere Lösung darin bestehen, Kopien auszugeben, damit der aufrufende Code das Array nicht mutieren kann. Dies ist, was ich normalerweise tun würde, aber es kann nicht in Ihrer Situation angemessen sein.
%Vor%Ohne zusätzlichen Schutz gibt es keine Garantie , dass ein Lese-Thread jemals den neuen Wert sehen wird. Solange der Lese-Thread etwas Bedeutendes tut, wird den neuen Wert sehen. Insbesondere werden Sie niemals "die Hälfte" eines Updates sehen, mit einem Verweis auf Totraum.
Wenn du das Feld volatile
machst, glaube ich, dass selbst diese Gefahr beseitigt ist - aber Lock-Free-Programmierung ist im Allgemeinen schwer zu verstehen. Dies bedeutet natürlich, dass es aufgegeben wird, eine automatisch implementierte Eigenschaft zu sein.
Es hängt davon ab, was Sie mit thread-safe meinen.
Das Lesen und Ersetzen ist garantiert atomar, aber es ist nicht garantiert, dass ein Lesen nach einem Schreibvorgang notwendigerweise den neuen Wert liest.
Als Reaktion auf Ihre Bearbeitung ...
Mit Ihrem vorhandenen Code wird nichts Schlimmes passieren (z. B. zerrissene Lesevorgänge), aber es gibt keine Garantie dafür, dass Ihre Leser den neuen Wert sehen werden . Zum Beispiel ist es möglich - wenn auch vielleicht unwahrscheinlich -, dass die alte Referenz für immer in einem Register zwischengespeichert wird.
Dies ist nicht threadsicher. Ja, Sie müssen ein Schloss verwenden.
Ich würde sperren. Verwenden Sie für mehrfaches Lesen gelegentliches Schreiben ein ReaderWriterLockSlim - viel effizienter als ReaderWriteLock .
%Vor%Um etwas vom Thema abzuweichen, fügt das Java 2 1.5-Speichermodell zwei Garantien hinzu (siehe Java-Theorie und Übung: Reparieren des Java-Speichermodells, Teil 2 ):
final
-Felder werden außerhalb des Konstruktors vollständig initialisiert. Letzteres ist ein interessanter Fall: Sie konnten foo = new String(new char[]{'a','b','c'});
in einem Thread und foo = "123"; System.out.println(foo)
in einem anderen Thread verwenden und die leere Zeichenfolge drucken, weil es keine Garantie gab, dass die Schreibvorgänge in foos letzte Felder stattfinden vor dem Schreiben zu foo.
Ich bin mir nicht sicher über die Details der .NET-Array-Initialisierung; Möglicherweise müssen Sie Thread.MemoryBarrier () (am Anfang des Getters und am Ende des Setter) verwenden, um sicherzustellen, dass die Leser nur vollständig initialisierte Arrays sehen.
Tags und Links c# multithreading thread-safety static