Frage

Dies ist eine komplexe Frage. Überlegen Sie sich bitte sorgfältig vor der Beantwortung.

Betrachten Sie diese Situation. Zwei Threads (ein Leser und ein Schriftsteller) greifen auf eine einzelne Global zu int. Ist das sicher? Normalerweise würde ich ohne Gedanken antworten, ja!

Es scheint mir jedoch, dass Herb Sutter das nicht glaubt. In seinen Artikeln über effektive Parallelität diskutiert er a fehlerhafte lockfreie Warteschlange und die korrigierte Version.

Am Ende des ersten Artikels und zu Beginn des zweiten diskutiert er eine selten angesehene Merkmale von Variablen, Schreiben. INTs sind atomic, gut, aber INTs sind nicht unbedingt bestellt, was jeden lockfreien Algorithmus, einschließlich meines oben genannten Szenarios, zerstören könnte. Ich stimme voll und ganz zu, dass der einzige Weg dazu Garantie Das korrekte Multithread -Verhalten auf allen vorhandenen Plattformen und Zukunft besteht darin, die Atomik (AKA -Speicherbarrieren) oder Mutexes zu verwenden.

Meine Frage; Ist Write Reodering jemals ein Problem auf echter Hardware? Oder ist die Multithread -Paranoia nur pedantisch?
Was ist mit klassischen UniProcessor -Systemen?
Was ist mit einfacheren RISC-Prozessoren wie einem eingebetteten Power-PC?

Klärung: Ich interessiere mich mehr für das, was Herr Sutter über die Hardware (Prozessor/Cache) -Rehre -Variable sagte. Ich kann den Optimierer daran hindern, den Code mit Compiler-Switches oder Handprüfung der Montage nach der Kompilierung zu brechen. Ich würde jedoch gerne wissen, ob die Hardware den Code in der Praxis immer noch durcheinander bringen kann.

War es hilfreich?

Lösung

Ihre Idee, die Versammlung zu inspizieren, ist nicht gut genug. Die Neuordnung kann auf Hardwareebene erfolgen.

Um Ihre Frage zu beantworten: "Ist dies jemals ein Problem in der Lesen von Hardware:" Ja! Tatsächlich bin ich selbst auf dieses Problem gestoßen.

Ist es in Ordnung, das Problem mit Uniprocessor-Systemen oder anderen Sonderpase-Situationen zu umrocken? Ich würde "nein" argumentieren, weil Sie in fünf Jahren möglicherweise doch mit Multi-Core laufen müssen, und dann wird es schwierig sein, all diese Standorte zu finden (unmöglich?).

Eine Ausnahme: Software, die für eingebettete Hardwareanwendungen entwickelt wurde, bei denen Sie tatsächlich die Hardware vollständig kontrollieren. Tatsächlich habe ich in diesen Situationen auf einem Armprozessor solche "betrogen".

Andere Tipps

Yup - Verwenden Sie Speicherbarrieren, um bei Bedarf eine Neuordnung des Befehls zu verhindern. In einigen C ++ - Compilern wurde das volatile Schlüsselwort erweitert, um implizite Speicherbarrieren für jedes Lese- und Schreiben einzufügen - dies ist jedoch keine tragbare Lösung. (Ebenso mit den ineinandergreifenden* Win32 -APIs). Vista fügt sogar einige neue, feinkörnige Verriegelungs-APIs hinzu, mit denen Sie Semantik lesen oder schreiben können.

Leider hat C ++ ein so loses Speichermodell, dass jede Art von Code wie dieser in gewissem Maße nicht portierbar ist und Sie verschiedene Versionen für verschiedene Plattformen schreiben müssen.

Wie Sie sagten, benötigen Sie aufgrund der Neuordnung auf Cache- oder Prozessorebene tatsächlich eine Art Speicherbarriere, um eine ordnungsgemäße Synchronisation sicherzustellen, insbesondere für Multi-Prozessoren (und insbesondere für nicht x86 Plattformen). (Ich bin der Annahme, dass Systeme mit Einzelprozessoren diese Probleme nicht haben, aber mich nicht dazu zitieren-ich bin sicherlich eher geneigt, sicher zu spielen und den synchronisierten Zugriff trotzdem zu machen.)

Wir sind auf das Problem gestoßen, wenn auch auf ITANIUM -Prozessoren, bei denen die Anweisung aggressiver als x86/x64 ist.

Die Lösung bestand darin, einen unverstockten Anweisungen zu verwenden, da es (zu diesem Zeitpunkt) dem Compiler (zu diesem Zeitpunkt) einfach nur eine Schreibbarriere nach der Aufgabe anforderte.

Wir brauchen wirklich eine Sprachverlängerung, um mit diesem sauber damit umzugehen. Die Verwendung von flüchtigem (wenn vom Compiler unterstützt) ist zu grobkörnig für die Fälle, in denen Sie versuchen, so viel Leistung wie möglich aus einem Stück Code herauszuholen.

Ist das jemals ein Problem bei echten Hardware?

Absolut, besonders jetzt mit dem Umzug in mehrere Kerne für aktuelle und zukünftige CPUs. Wenn Sie von der geordneten Atomizität angewiesen sind, um Funktionen in Ihrer Anwendung zu implementieren, können Sie diese Anforderung nicht über Ihre ausgewählte Plattform oder die Verwendung von Synchronisation -Primitiven untersuchen, unter alle Bedingungen IE Der Kunde wechselt von einer Single-Core-CPU zu Multi-Core-CPU, dann warten Sie nur auf ein Problem.

Zitat aus dem in Bezug auf Herb Sutter Artikel (zweiten)

Ordnungsgeordnete Atomvariablen werden auf populären Plattformen und Umgebungen auf unterschiedliche Weise geschrieben. Zum Beispiel:

  • volatile in c#/. net, wie in volatile int.
  • volatile oder * atomic * in Java, wie in volatile int, AtomicInteger.
  • atomic<T> In C ++ 0x ist der bevorstehende ISO C ++ - Standard wie in atomic<int>.

Ich habe nicht gesehen, wie C ++ 0x die geordnete Atomizität implementiert hat, daher kann ich nicht angeben, ob die bevorstehende Sprachfunktion eine reine Implementierung von Bibliothek ist oder auch auf Änderungen der Sprache beruht. Sie können den Vorschlag überprüfen, um festzustellen, ob er als nicht standardmäßige Erweiterung Ihrer aktuellen Werkzeugkette aufgenommen werden kann, bis der neue Standard verfügbar ist. Es ist möglicherweise sogar für Ihre Situation verfügbar.

Es ist ein Problem bei echten Hardware. Ein Freund von mir arbeitet für IBM und verdient seinen Lebensunterhalt in erster Linie, indem er diese Art von Problem in den Kundencodes ausgeht.

Wenn Sie sehen möchten, wie schlimm die Dinge werden können, suchen Sie nach akademischen Papieren im Java -Speichermodell (und jetzt auch das C ++ - Speichermodell). Angesichts der Neuordnung, dass echte Hardware möglich ist, ist es ein Albtraum, herauszufinden, was in einer hochrangigen Sprache sicher ist.

Nein, das ist nicht sicher und es gibt echte Hardware -Avaiialble, die dieses Problem aufweist, zum Beispiel das Speichermodell im PowerPC -Chip auf Xbox 360 ermöglicht es, die Schreibvorgänge neu zu bestellen. Dies wird durch den Mangel an Hindernissen in den Intrinsikern verschärft, siehe diesen Artikel über msdn für mehr Details.

Die Antwort auf die Frage "Ist es sicher" ist von Natur aus mehrdeutig.

Es ist immer sicher, selbst für Doppel, in dem Sinne, dass Ihr Computer kein Feuer fängt. Es ist sicher, in dem Sinne, dass Sie immer einen Wert erhalten, den der INT irgendwann in der Vergangenheit gehalten hat, ist es nicht sicher, in dem Sinne, dass Sie einen Wert erhalten, der von einem anderen Thread aktualisiert wird.

"Atomic" bedeutet, dass Sie die zweite Garantie erhalten. Da das Doppel normalerweise nicht atomar ist, können Sie 32 alte und 32 neue Bits erhalten. Das ist eindeutig unsicher.

Als ich die Frage stellte, interessierte ich mich am meisten an Uniprocessor Powerpc. In einem der Kommentare Incitek Jeff erwähnte die PowerPC -Synchronisierungs- und Isync -Anweisungen. Diejenigen, bei denen der Schlüssel zu einer endgültigen Antwort. ich habe es gefunden hier Auf der Website von IBM.

Der Artikel ist groß und ziemlich dicht, aber das Weg ist nein, er ist nicht sicher. Bei älteren PowerPCs The Memory -Optimierern, die nicht raffiniert genug sind, um Probleme auf einem Uniprozessor zu verursachen. Die neueren sind jedoch viel aggressiver und können sogar einen einfachen Zugang zu einem globalen INT brechen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top