web-dev-qa-db-de.com

Atomisches Verhalten von unären Inkrementoperatoren

Ich habe irgendwo gelesen, dass unäre Operatoren von Natur aus atomar sind und daher in einer Multi-Thread-Umgebung verwendet werden können. Um das zu bestätigen, habe ich zwei separate Programme in geschrieben 

  1. Ich habe eine Variable x verwendet und mit dem unären Operator ++ x inkrementiert
  2. Ich habe eine Variable x verwendet und mit x = x + 1 inkrementiert

Ich verglich die Demontage beider Programme und fand keinen Unterschied. Bitte geben Sie Ihre Eingaben dazu an.

8
user3505805

Ich habe irgendwo gelesen, dass unäre Operatoren von Natur aus atomar sind und daher in einer Multi-Thread-Umgebung verwendet werden können. 

Diese Quelle ist völlig falsch. Sie müssen std::atomic (oder das C-Äquivalent) verwenden, um Atomizität zu erreichen - unäre Operationen sind nicht speziell.


Ich verglich die Demontage beider Programme und fand keinen Unterschied

Das bedeutet nicht, dass die generierten Operationen atomar sind. Es gibt keinen Unterschied, da ein anständiger Compiler x=x+1 und ++x in derselben Assembly optimiert (vorausgesetzt, es werden integrierte Typen verwendet).

13
Vittorio Romeo

Beim Schreiben von plattformübergreifendem C++ haben Sie bei Verwendung von std::atomic<> nur atomares Verhalten. 

Es ist wahr, dass der Prozessor auf bestimmten Plattformen wie Intel 64bit garantiert, dass inc atomar ist. Schreiben Sie jedoch keinen Code, der davon abhängt! Als zukünftiger Debugger würde ich gerne wissen, welche Daten über Threads gemeinsam genutzt werden sollen und welche nicht. 

Die Verwendung von std::atomic<int> ist zwar etwas mehr Arbeit beim Schreiben, garantiert jedoch, dass sich alles atomar (auf jeder Plattform) verhält, indem entweder auf die Plattformanforderungen ( std :: atomic :: is_lock_free ) oder explizit zurückgegriffen wird den Zugang verriegeln. Setzen Sie außerdem Schutzvorrichtungen ein, um sicherzustellen, dass die Caches der anderen Prozessorkerne ungültig werden (falls die Plattform dies erfordert).

In der Praxis für Intel 64bit sollte dies die gleiche Assembly ergeben. Wenn dies nicht der Fall ist, melden Sie einen Fehler in Ihrem Compiler.

Zur gleichen Zeit sind einige Operationen mit ints möglicherweise nicht atomar (Operator * =). std::atomic hält diese Operationen einfach nicht, sodass Sie korrekt mit diesen arbeiten müssen.

Nebenbei bemerkt: ++x und x = x+1 sind verschiedene Operationen, sie können für die gleiche Assembly optimiert werden. Angesichts nicht-atomarer Plattformanforderungen ist der zweite plötzlich ein Fehler, dessen Lösung Tage dauert.

5
JVApen

Die Behauptung, dass ein unärer Operator notwendigerweise atomar ist, ist ein Mythos.

Zum Beispiel erfordert ++x ein Lesen und Schreiben in x, damit die Chance eines Datenrennens eröffnet wird.

Die Tatsache, dass ++x zu demselben Code wie x = x + 1 kompiliert wird, ist nicht relevant.

Wenn Sie Datenrennen vermeiden möchten, verwenden Sie atomare Typen oder Einheiten zum gegenseitigen Ausschluss, wenn kein geeigneter atomarer Typ verfügbar ist. Zur Vermeidung von Zweifeln ist int nicht notwendigerweise ein atomarer Typ.

5
Bathsheba

Irgendwo habe ich gelesen, dass unäre Operatoren von Natur aus atomar sind und daher kann verwendet werden, wie es in einer Multi-Threaded-Umgebung ist.

Das ist falsch x++ erfordert zum Beispiel ein Laden von x, ein Addieren und ein Speichern von x. Diese Anweisungen sind von Natur aus nicht atomar.

4

Nicht wahr. Selbst wenn es wäre, welchen Grund hätte https://en.cppreference.com/w/cpp/atomic/atomic#Type_aliases dann? 

Ich denke, was sie wahrscheinlich gemeint haben, ist, dass eine Berechnung für eine solche Operation normalerweise sehr winzig ist und daher höchstwahrscheinlich niemals eine Race-Bedingung hat, was meistens im Live-Code der Fall ist, bei dem Sie nicht x ++ in 4 für Schleifen gleichzeitig berechnen.

2
anon

Sie haben den Typ von x nicht angegeben. 

  1. Wenn x eine 32-Bit-Ganzzahl ist, wenn die Plattform 16 oder 8 Bit ist, führt die Operation "x ++" Definitiv mehrere Operationen aus
  2. x könnte sogar kein Basistyp sein, x könnte eine Instanz von Class sein, bei der Operator ++ viel kompliziertere Dinge tut, als nur die Ganzzahl zu erhöhen
2
Vladimir A.

Die Atomizität der Operation stronglr hängt vom Zielsystem ab. Der unäre Betrieb ist auf RMW-Systemen wie RISC-Mikrocontrollern möglicherweise nicht atomar.

Für diese Frage gibt es keine allgemeine Antwort.

1
P__J__

Sie machen eine Annahme in Bezug auf den generierten Code. Wenn nur eine Anweisung generiert wird, wird sie atomar sein, andernfalls nein.

In Ihrem Fall wird davon ausgegangen, dass der Zielprozessor die Anweisung inc <address> hat und der Compiler diese erzeugen wird.

0
bruno

Atomisches Verhalten unärer Operatoren

In C sind pre/post fix ++ keine unary-Operatoren wie & * + - ~ !. aber ein Teil eines unary-Ausdrucks . Der Fragentitel stimmt also nicht mit dem Körper überein.

Sogar ein unärer Operator wie + ist nicht atomar, da der Zugriff auf das Objekt (denke long long) mehrere Op-Code-Lesevorgänge erfordert.

0
chux