2009-02-04 17 views
8

Sind boolesche Variablen Thread-sicher zum Lesen und Schreiben von einem Thread? Ich habe einige Newsgroup-Referenzen gesehen, um zu sagen, dass sie das sind. Sind andere Datentypen verfügbar? (Aufzählungstypen, vielleicht kleine Ints?)Liste der Delphi-Datentypen mit "thread-safe" Lese-/Schreiboperationen?

Es wäre nett, eine Liste aller Datentypen zu haben, die sicher aus jedem Thread gelesen werden können, und eine andere Liste, in die ohne Weiteres geschrieben werden kann zu verschiedenen Synchronisationsmethoden.

Antwort

7

Bitte beachten Sie, dass Sie im Wesentlichen alles in Delphi undhreadsafe machen können. Während andere auf boolesche Ausrichtungsprobleme hinweisen, verbirgt sich auf diese Weise das eigentliche Problem.

Ja, Sie können einen Booleschen Wert in einem beliebigen Thread lesen und in einen beliebigen Booleschen Wert schreiben, wenn er korrekt ausgerichtet ist. Aber das Lesen von einem Booleschen, das du änderst, ist sowieso nicht unbedingt "threadsicher". Angenommen, Sie haben einen booleschen Wert, den Sie auf "true" setzen, wenn Sie eine Zahl aktualisiert haben, sodass ein anderer Thread die Zahl liest.

if NumberUpdated then 
begin 
    LocalNumber = TheNumber; 
end; 

Durch Optimierungen macht der Prozessor thenumber gelesen werden kann, bevor NumberUpdated gelesen wird, so können Sie den alten Wert von thenumber erhalten eventhough Sie NumberUpdated zuletzt aktualisiert wurden.

Aka, kann Ihr Code werden:

temp = TheNumber; 
if NumberUpdated the 
begin 
    LocalNumber = temp; 
end; 

Imho, eine Faustregel:
". Liest sind Thread-sicher Writes nicht Thread-sicher sind"
Also, wenn Sie einen Schreibschutz die Daten mit der Synchronisation überall Sie lesen den Wert, während ein Schreiben könnte potenziell auftreten.
Auf der anderen Seite, wenn Sie nur einen Wert in einem Thread lesen und schreiben, dann ist es threadsicher. So können Sie einen großen Teil des Schreibens an einem temporären Speicherort ausführen und dann ein Update der anwendungsweiten Daten synchronisieren.

Bonus Klappentext:

Die VCL ist nicht Thread-sicher. Behalte alle Modifikationen von ui stuff im Hauptthread. Behalte die Erstellung aller UI-Sachen auch im Hauptthread.

Viele Funktionen sind auch nicht threadsicher, während andere oft von den zugrunde liegenden winapi-Aufrufen abhängen.

Ich glaube nicht, dass eine "Liste" hilfreich wäre, da "thread safe" eine Menge Zeug bedeuten kann.

+0

+1, sehr gute Punkte. Interessierte können sich beispielsweise http://en.wikipedia.org/wiki/Memory_barrier und die verlinkten Informationen ansehen. – mghie

5

In der 32-Bit-Architektur sollten nur ordnungsgemäß ausgerichtete 32-Bit-Datentypen als atomar betrachtet werden. 32-Bit-Werte müssen 4-ausgerichtet sein (die Adresse der Daten muss durch 4 teilbar sein). Sie würden wahrscheinlich nicht auf solch engem Niveau in Interleaving laufen, aber theoretisch könnten Sie Double, Int64 oder Extended nicht-atomaren schreiben.

+0

Seit geraumer Zeit ist das ausgerichtete 64-Bit-Lesen/Schreiben atomar auf x86-Hardware, sogar im 32-Bit-Modus –

+0

Seit der Einführung von Multi-Core- und Multi-Prozessor-Architekturen ist die Ausrichtung keine Garantie mehr. Ich habe dies einmal selbst mit einigen extrem kurzen Threads bewiesen, die passend ausgerichtete Daten mit Schreibvorgängen hämmerten, während andere Threads versuchten, sie zu lesen. Die Leser wurden codiert, um Ausnahmen auszulösen, wenn die gelesenen Werte nicht in einer Reihe von Werten lagen, die die Schreiber geschrieben hatten. –

7

Dies ist keine Frage von Dateitypen, die Thread-sicher sind, aber es ist eine Frage dessen, was Sie mit ihnen tun. Ohne Sperren ist keine Operation threadsicher, das heißt das Laden eines Wertes, dann das Ändern und dann das Zurückschreiben: das Inkrementieren oder Dekrementieren einer Zahl, das Löschen oder Setzen eines Elements in einem Satz - sie sind alle nicht Thread-sicher.

Es gibt eine Reihe von Funktionen, die atomare Operationen ermöglichen: verriegelte Inkrementierung, verriegelte Dekrementierung und verriegelter Austausch. Dies ist ein allgemeines Konzept, nichts speziell für Windows, x86 oder Delphi. Für Delphi können Sie die InterlockedFoo() - Funktionen der Windows-API verwenden, um diese herum gibt es auch mehrere Wrapper. Oder schreibe deine eigenen. Die Funktionen arbeiten mit ganzen Zahlen, so dass Sie atomare Inkremente, Dekremente und den Austausch von ganzen Zahlen (32 Bit) mit ihnen haben können.

Sie können auch Assembler- und Präfix-Ops mit dem Sperrpräfix verwenden.

Für weitere Informationen siehe auch this StackOverflow Frage.

0

Indy Code enthält einige atomare/Thread sichere Datentypen in IdThreadSafe.pas:

  • TIdThreadSafeInteger
  • TIdThreadSafeBoolean
  • TIdThreadSafeString
  • TIdThreadSafeStringList und einige mehr ...
1

Mit Multi-Core-RISC-Verarbeitung und separaten Kern c Da das Gedächtnis in der Mischung eines modernen Prozessors liegt, ist es nicht länger der Fall, dass irgendeine "triviale" Hochsprache-Lese- oder Schreibkonstrukte (oder in der Tat viele einmal auf einmal 8086 "atomare" Assembleranweisungen) konstruiert werden) kann als atomar angesehen werden. In der Tat, es sei denn, ein Assemblerbefehl ist speziell atomar konstruiert, ist er wahrscheinlich nicht atomar - und das schließt die meisten Mechanismen für Speicherlesevorgänge ein. Selbst eine lange Ganzzahl, die auf Assembler-Ebene gelesen wird, kann durch simultanes Schreiben von einem anderen Prozessorkern, der denselben Speicher teilt und asynchrone Cache-Aktualisierungsaktionen auf der RISC-Prozessor-Ebene verwendet, beschädigt werden. Denken Sie daran, dass auf einem Prozessor mit mehreren RISC-Kernen selbst Assemblersprachanweisungen nur "höhere" Codeanweisungen sind! Sie wissen nie wirklich, wie sie auf der Bit-Ebene implementiert werden, und es ist vielleicht nicht ganz das, was Sie erwartet haben, wenn Sie ein altes 8086 (Single-Core) Assembler-Handbuch gelesen haben. Windows stellt native Systemkompatible atomare Operatoren zur Verfügung, und Sie wären gut beraten, diese zu verwenden, anstatt irgendwelche Grundannahmen über atomare Operationen zu machen.

Warum die Windows-Operatoren verwenden? Eines der ersten Dinge, die Windows tut, ist festzustellen, auf welcher Maschine es läuft. Einer der Schlüsselaspekte, die es sicherstellen, ist, was atomare Operationen dort sind und wie sie funktionieren. Wenn Sie möchten, dass Ihr Code bei zukünftigen Prozessoren gut in die Zukunft passt, können Sie diesen Aufwand in Ihrem eigenen Code duplizieren (und ständig aktualisieren), oder Sie können die Tatsache nutzen, dass Windows bereits beim Start alles erledigt hat. Es integrierte dann den notwendigen Code zur Laufzeit in seine API.

Lesen Sie die MSDN-Seiten zu atomaren Operationen. Die Windows API zeigt diese für Sie an. Manchmal wirken sie klobig oder ungeschickt - aber sie sind zukunftssicher und funktionieren immer genau so, wie es auf der Verpackung steht.

Woher weiß ich das? Nun, denn wenn sie es nicht tun würden - dann könnten Sie Windows nicht ausführen. Punkt. Es macht nichts, einen eigenen Code zu erstellen. Wenn Sie Code schreiben, ist es immer eine gute Idee, Parsimony zu verstehen und Occam's razor zu betrachten. Mit anderen Worten, wenn Windows dies bereits tut und Ihr Code Windows zum Ausführen benötigt, dann verwenden Sie, was Windows bereits tut, anstatt viele alternative und zunehmend komplexe hypothetische Lösungen auszuprobieren, die funktionieren können oder nicht. Etwas anderes zu tun ist nur eine Verschwendung von Zeit (es sei denn natürlich, dass Sie das sind).