Kann man einen einfachen Thread mit statischen Eigenschaften erhalten und setzen? [Duplikat]

8

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.

    
xsl 19.08.2010, 16:07
quelle

6 Antworten

10

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%     
Jeffrey L Whitledge 19.08.2010, 17:08
quelle
7

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.

    
Jon Skeet 19.08.2010 16:29
quelle
5

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.

    
LukeH 19.08.2010 16:12
quelle
2

Dies ist nicht threadsicher. Ja, Sie müssen ein Schloss verwenden.

    
James Gaunt 19.08.2010 16:08
quelle
1

Ich würde sperren. Verwenden Sie für mehrfaches Lesen gelegentliches Schreiben ein ReaderWriterLockSlim - viel effizienter als ReaderWriteLock .

%Vor%     
Michael 19.08.2010 16:42
quelle
1

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 ):

  • flüchtige Lese- / Schreibvorgänge sind auch Speicherbarrieren.
  • 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.

    
tc. 19.08.2010 18:59
quelle