Ist es sicher, den booleschen Wert im Thread von einem anderen zu setzen?

8

Ich frage mich, ob der folgende (Pseudo-) Code sicher zu verwenden ist. Ich weiß über beendetes Flag, aber ich muss eine Art Cancel-Flag bei rekursiver Suche aus dem Haupt-Thread setzen und den Worker-Thread laufen lassen. Ich werde dort auch die Terminated-Eigenschaft prüfen, was in diesem Pseudocode fehlt.

%Vor%

Ist es sicher, die boolesche Eigenschaft FCancel innerhalb des Threads auf diese Weise zu setzen? Würde dies nicht mit dem Lesen dieses Flags in der RecursiveSearch-Prozedur kollidieren, während die Schaltfläche im Hauptformular (Hauptthread) gedrückt wird? Oder muss ich z. kritischer Abschnitt zum Lesen und Schreiben dieses Wertes?

Vielen Dank

    
Martin Reiner 08.03.2012, 16:11
quelle

4 Antworten

16

Es ist absolut sicher, dies zu tun. Der Lese-Thread liest immer entweder wahr oder falsch. Es wird kein Tearing geben, weil Boolean nur ein einzelnes Byte ist. In der Tat gilt das Gleiche für einen ausgerichteten 32-Bit-Wert in einem 32-Bit-Prozess, d. H.% Co_de%.

Dies ist, was als benign race bekannt ist. Es gibt eine Race-Bedingung für die boolesche Variable, da ein Thread liest, während ein anderer Thread ohne Synchronisation schreibt. Aber die Logik dieses Programms wird durch das Rennen nicht beeinträchtigt. In komplexeren Szenarien könnte ein solches Rennen schädlich sein, und dann wäre eine Synchronisierung erforderlich.

    
David Heffernan 08.03.2012, 16:17
quelle
7

Das Schreiben in ein boolesches Feld aus verschiedenen Threads ist Thread-sicher - das heißt, die Schreiboperation ist atomar. Kein Beobachter des Feldes wird jemals einen "Teilwert" sehen, da der Wert in das Feld geschrieben wird. Bei größeren Datentypen sind partielle Schreibvorgänge eine echte Möglichkeit, da mehrere CPU-Anweisungen erforderlich sind, um den Wert in das Feld zu schreiben.

Also ist das tatsächliche Schreiben des booleschen Wertes kein Thread-Sicherheitsproblem. Wie Beobachter dieses boolesche Feld verwenden, kann jedoch ein Threadsicherheitsproblem sein. In Ihrem Beispiel ist die RecursiveSearch-Funktion der einzige sichtbare Beobachter und die Verwendung des FCancel-Werts ist ziemlich einfach und harmlos. Der Beobachter des FCancel-Status ändert den FCancel-Status nicht, daher handelt es sich um eine direkte / azyklische Abhängigkeit vom Producer-Consumer-Typ.

Wenn der Code stattdessen das boolesche Feld verwendet, um zu bestimmen, ob eine einmalige Operation ausgeführt werden muss, reichen einfache Lese- und Schreibvorgänge im booleschen Feld nicht aus, da der Beobachter des booleschen Feldes das Feld ebenfalls ändern muss (um zu markieren, dass die einmalige Operation durchgeführt wurde). Das ist ein Read-Modify-Write-Zyklus, und das ist nicht sicher, wenn zwei oder mehr Threads genau zur richtigen Zeit dieselben Schritte ausführen. In diesem Fall können Sie eine Mutex-Sperre um die einmalige Operation legen (und boolesche Feldprüfung und -aktualisierung), oder Sie können InterlockedExchange verwenden, um das boolesche Feld ohne Mutex zu aktualisieren und zu testen. Sie könnten die einmalige Operation auch in einen statischen Typkonstruktor verschieben und müssen keine Sperren selbst verwalten (obwohl .NET dafür Sperren hinter den Kulissen verwendet).

    
dthorpe 08.03.2012 16:37
quelle
4

Ich stimme zu, dass das Schreiben eines booleschen Wertes aus einem Thread und das Lesen aus einem anderen threadsicher ist. Seien Sie jedoch vorsichtig mit inkrementieren - dies ist nicht atomar und kann abhängig von der Implementierung eine eindeutig nicht-benotete Race-Bedingung in Ihrem Code verursachen. Inkrement / Dekrement wird normalerweise in drei separate Maschinenanweisungen umgewandelt - Laden / Aufnehmen / Speichern.

Dies ist, was die InterlockedIncrement, InterlockedDecrement und InterlockedExchange Win32-API-Aufrufe sind für - 32-Bit-Inkrement, Dekrementieren und Laden, um atomar ohne ein separates Synchronisierungsobjekt auftreten zu ermöglichen.

    
Dean Roberson 08.03.2012 17:38
quelle
3

Ja, es ist sicher, Sie müssen Kritische Abschnitte nur verwenden, wenn Sie von / zu einem anderen Thread lesen oder schreiben, innerhalb desselben Threads ist es sicher.

Übrigens. Wie Sie die RecursiveSearch-Methode definiert haben, if (FCancel = False), dann erhalten Sie einen Stack overflow (:

    
ComputerSaysNo 08.03.2012 16:18
quelle