Ist i=5 eine atomare Operation?



  • Hallo liebe Forumsmitglieder,

    ich wolte wissen, ob eine Wertzuweisung oder das Auslesen eines Wertes
    bei einer Variable vom Typ int oder unsigned int atomar ist.
    Ich habe "gesuchmaschint", aber nur gefunden, dass evtl. das Auslesen und Schreiben
    bei long long nicht atomar ist.

    Hoffe mir kann jemand helfen.
    Grüße Yamaha27


  • Mod

    Kommt halt drauf an. Wenn der Compiler die richtigen Instruktionen erzeugt, und wenn das Programm auf der richtigen Art von Maschine läuft, und wenn die Daten auch korrekt ausgerichtet sind, dann kann man sicher sein, dass es atomic ist, ja. Aber vom C-Standard garantiert wird davon nichts, das geht nur aus den Handbüchern für die spezielle Maschine hervor. Komisch, dass du dazu angeblich nichts gefunden hast, Suchbegriffe wie "c int atomic" bringen einen direkt zu sehr guten Antworten, zum Beispiel dieser Zusammenfassung hier.

    Empfehlung: C11 bringt stdatomic.h, dort findet man Operationen, die garantiert atomic sind und wo einem nichts dazwischen funken kann, ohne dass man sich auf Assemblerniveau herab begeben muss. Insbesondere wird dort auch atomic test-and-set angeboten, etwas was man sonst ohne Assembler unmöglich hin bekommen kann. Und vermutlich ist das doch die Schlüsselanweisung, denn wenn jemand nach atomics fragt, will er meistens einen Mutex basteln.



  • Danke für die schnelle Antwort.
    Ich hab die ganze Zeit nur auf deutsch gesucht.
    Kein Wunder also, dass ich nichts gefunden habe.
    Und danke für den Hinweis auf die Bibliothek.

    Zwei Fragen zu deinem Beitrag habe ich aber noch:

    Wenn der Compiler die richtigen Instruktionen erzeugt, und wenn das Programm auf der richtigen Art von Maschine läuft, und wenn die Daten auch korrekt ausgerichtet sind, dann kann man sicher sein, dass es atomic ist, ja.

    Was meinst du mit Daten richtig ausgerichtet?

    Und vermutlich ist das doch die Schlüsselanweisung, denn wenn jemand nach atomics fragt, will er meistens einen Mutex basteln.

    Was meinst du damit? Ich will ja wissen, ob ich den(?) Mutex vermeiden kann, weil ich nur in eine int-Variable schreibe und sie auslese.

    Yamaha27



  • Weiß jetzt nicht, ob das etwas off-topic ist, aber ich folge immer noch Mr. Newcomer:
    "the best synchronization is no synchronization"
    atomic hin oder her - eine zentrale Funktion verarbeitet und verwaltet alle Daten von allen threads. Ist ne sichere und zuverlässige Sache ohne Mutex oder lock oder sowas.


  • Mod

    Yamaha27 schrieb:

    Ich hab die ganze Zeit nur auf deutsch gesucht.
    Kein Wunder also, dass ich nichts gefunden habe.

    Ja, das erklärt, warum du nichts gefunden hast. In der Computerei geht eben nichts ohne Englisch. Allerhöchstens zu Anfängerthemen kann man im deutschsprachigen Raum noch fündig werden (dann meistens in Form einer Übersetzung). Atomic Operationen zählen da ganz sicher nicht mehr dazu.

    Zwei Fragen zu deinem Beitrag habe ich aber noch:

    Wenn der Compiler die richtigen Instruktionen erzeugt, und wenn das Programm auf der richtigen Art von Maschine läuft, und wenn die Daten auch korrekt ausgerichtet sind, dann kann man sicher sein, dass es atomic ist, ja.

    Was meinst du mit Daten richtig ausgerichtet?

    Vorausgesetzt natürlich die anderen erwähnten Voraussetzungen sind erfüllt und wir befinden uns auf einem x86er-System: Datenworte haben auf dieser Art System eine natürliche Ausrichtung, zu Englisch Alignment. Ein int, der auf dieser Art von System normalerweise aus 4 Bytes besteht, muss an einer Adresse stehen, die auch durch 4 teilbar ist, damit sie vom System in einem Rutsch verarbeitet werden kann. Wenn der int nicht an solch einer Adresse steht, dann muss das System für den Zugriff zunächst die beiden 4-Byte-Blöcke lesen, in denen der int verteilt ist und dann ein bisschen rumrechnen, um aus diesen beiden Blöcken die 4 Byte zu extrahieren, die den gewünschten int ausmachen und dann noch ein bisschen mehr rechnen, um sie zu dem gewünschten int zusammen zu setzen*. Dieser gesamte Vorgang ist dann natürlich nicht mehr atomic.

    Normalerweise wird ein Compiler Code erzeugen, bei dem alle Datentypen ihrer natürlichen Ausrichtung folgen, allein schon, weil der so erzeugte Code viel schneller ist (weil das ganze Gerechne entfällt). Aber es ist erstens nicht garantiert, dass das so sein muss (außer man benutzt eben die speziellen atomic-Datentypen aus stdatomic.h) und zweitens gibt es Mechanismen, mit denen man den Compiler dazu zwingen kann, nicht die natürliche Ausrichtung einzuhalten, beispielsweise Compilerschalter, das Programm auf Speicherverbrauch zu optimieren, aber zum Beispiel auch wilde Pointercasts zwischen nicht gleich ausgerichteten Typen.

    Und vermutlich ist das doch die Schlüsselanweisung, denn wenn jemand nach atomics fragt, will er meistens einen Mutex basteln.

    Was meinst du damit? Ich will ja wissen, ob ich den(?) Mutex vermeiden kann, weil ich nur in eine int-Variable schreibe und sie auslese.

    Das war dann das andere Szenario, das ich mir ausmalen konnte, warum jemand diese Frage stellen könnte. Da in dem Fall aber bereits alles wichtige gesagt war, habe ich es nicht weiter erwähnt 🙂 . Beziehungsweise eine Sache ist noch zu erwähnen: Du kannst deinem zentralen int zwar atomic einen Wert zuweisen, aber das ändern eines Wertes nach einer Rechenvorschrift (also zum Beispiel i += 5 statt i = 5 ) ist nicht mehr unbedingt atomic. Da kann einfach zu viel schief gehen, wenn man das so im Code stehen hat. Dafür sind dann wieder die erwähnten Spezialoperationen aus stdatomic.h gut, bei denen garantiert ist, dass der passende Code erzeugt wird. Und in dem Fall braucht man dann auch tatsächlich keinen Mutex, was, wie EOP erwähnte, eine gute Sache ist.

    *: Das ist natürlich eine vereinfachte Darstellung. Aber so kann man es sich gut vorstellen.



  • Danke für die Antworten und die Erklärung.
    Yamaha27



  • SeppJ schrieb:

    Und in dem Fall braucht man dann auch tatsächlich keinen Mutex, was, wie EOP erwähnte, eine gute Sache ist.

    Hehe, bin manchmal etwas wortkarg. Erklärungen für manche Sachen gibt's nur auf Nachfrage.



  • EOP schrieb:

    "the best synchronization is no synchronization"
    atomic hin oder her - eine zentrale Funktion verarbeitet und verwaltet alle Daten von allen threads. Ist ne sichere und zuverlässige Sache ohne Mutex oder lock oder sowas.

    EOP schrieb:

    Hehe, bin manchmal etwas wortkarg. Erklärungen für manche Sachen gibt's nur auf Nachfrage.

    Zu Wortkarg.
    Ich hab' ziemlich viel Ahnung von multithreading, und ich hab' keinen Plan was du meinst.



  • @hustbaer: Ich glaube, er meint das so:

    Atomare Anweisungen sind Anweisungen, die aus einem Maschinenbefehl bestehen. Das heißt, in der Theorie kann kein anderer Thread dazwischenfunken, wenn ein atomarer Befehl für Variable a ausgeführt wird. Ein Thread könnte also atomar a was zuweisen, und damit sind dann keine Race-Conditions innerhalb dieser Zuweisung möglich.

    Aber in der Praxis stelle ich mir das nicht ganz so einfach vor. Weil wir inzwischen Multikernprozessoren haben, die gleichzeitig Anweisungen ausführen lassen könnten. Thread 1 weißt a 1 zu, und Thread 2 den Wert 2, und zwar zum gleichen Zeitpunkt. Während eine atomare Zuweisung reentrant ist, ist sie doch nicht wirklich threadsicher. Weil zwei Prozessoren gleichzeitig ihre Werte an den Memory Controller senden. Oder wie oder was?

    Würde auch hier gerne mehr dazu lesen wollen. Wenn du dich uns also erbarmen könntest, wäre das super.



  • EOP schrieb:

    atomic hin oder her - eine zentrale Funktion verarbeitet und verwaltet alle Daten von allen threads. Ist ne sichere und zuverlässige Sache ohne Mutex oder lock oder sowas.

    Das ist Quatsch.
    Jede Funktion kann jederzeit durch Auftreten eines Signals unterbrochen werden, und dann ist es vorbei mit "sicher und zuverlässig". Die Funktion müsste man extern mit sig_atomic_t schützen und da ist man dann schnell wieder bei Mutex und Konsorten.



  • dachschaden schrieb:

    Atomare Anweisungen sind Anweisungen, die aus einem Maschinenbefehl bestehen.

    Nö; atomare Operationen sind atomare Operationen weil sie atomare Operationen sind. Mit der Anzahl der "Maschinenbefehle" hat das absolut nix zu tun (in einer modernen CPU werden viele "Maschinenbefehle" erstmal gleich in einen Haufen µops zerlegt, weil die Schaltkreise mit "Maschinenbefehlen" direkt nix anfangen können), sondern nur damit, dass es eben "Maschinenbefehle" für gewisse atomare Operationen gibt.

    dachschaden schrieb:

    Das heißt, in der Theorie kann kein anderer Thread dazwischenfunken, wenn ein atomarer Befehl für Variable a ausgeführt wird. Ein Thread könnte also atomar a was zuweisen, und damit sind dann keine Race-Conditions innerhalb dieser Zuweisung möglich.

    Innerhalb der Zuweisung, das ist aber auch schon alles. Das macht den Code als ganzes noch lange nicht unbedingt threadsafe. Atomar heißt effektiv nur, dass die Operation selbst garantiert keinen Mist produziert, auch wenn mehrere Threads parallel überlappend was mit der betroffenen Speicherstelle anzustellen versuchen (effektiv sorgt die Hardware einfach dafür, dass solche Operationen auf der selben Speicherstelle immer irgendwie serialisiert werden). In welcher Reihenfolge nebenläufige Threads die Effekte von in anderen Threads ausgeführten, atomaren Operationen sehen ist aber z.B. damit noch lange nicht definiert und die nächste Race Condition lauert in der Regel gleich um die Ecke, nur für den Fall, dass du ihre 12 Kumpels hinter deinem Rücken schon bemerkt hast...

    dachschaden schrieb:

    Aber in der Praxis stelle ich mir das nicht ganz so einfach vor. Weil wir inzwischen Multikernprozessoren haben, die gleichzeitig Anweisungen ausführen lassen könnten. Thread 1 weißt a 1 zu, und Thread 2 den Wert 2, und zwar zum gleichen Zeitpunkt. Während eine atomare Zuweisung reentrant ist, ist sie doch nicht wirklich threadsicher. Weil zwei Prozessoren gleichzeitig ihre Werte an den Memory Controller senden. Oder wie oder was?

    Eine atomare Operation ist atomar, egal wie viele Cores deine CPU oder wie viele CPUs dein Rechner hat. Compiler und Hardware müssen das per Definition wie auch immer sicherstellen, sonst wäre es ja keine atomare Operation mehr. Und genau darum verwendet man besser die entsprechenden Sprachmittel, anstatt die Korrektheit des Codes von impliziten Annahmen über architekturspezifisches Verhalten abhängig zu machen, die man am besten wie die Ostereier schön vorsichtig quer über den ganzen Code verteilt versteckt hat...

    Die Antwort auf die Frage hier lautet ganz einfach

    Yamaha27 schrieb:

    [...]
    ich wolte wissen, ob eine Wertzuweisung oder das Auslesen eines Wertes
    bei einer Variable vom Typ int oder unsigned int atomar ist.

    Nein!



  • hustbaer schrieb:

    EOP schrieb:

    Hehe, bin manchmal etwas wortkarg. Erklärungen für manche Sachen gibt's nur auf Nachfrage.

    Zu Wortkarg.
    Ich hab' ziemlich viel Ahnung von multithreading, und ich hab' keinen Plan was du meinst.

    Vielleicht hast du es übersehen, aber ich habe gerade nachgefragt.


Anmelden zum Antworten