Thread safety / Atomarer Zugriff auf primitive Datentypen



  • Ich glaub du hast eine grundlegend falsche Vorstellung davon, wofür solche atomaren Operationen gut sind. Es ist jedenfalls nicht so, dass man einfach für Alles diese Funktionen benutzt und der Code dann auf magische Weise threadsafe wird. Abgesehen davon möchte ich nochmals betonen dass "atomarer Datentyp" keinen Sinn macht. Es gibt nur atomare Operationen. Die Aussage dass bool atomar wäre macht keinen Sinn. Und Operationen auf einem bool oder int oder sonstwas sind im Allgemeinen ganz gewiss nicht atomar.



  • Ich habe nie etwas von atomaren Datentypen geschrieben. Im Titel steht "Atomarer Zugriff auf primitive Datentypen" - damit sind Lese- und Schreibzugriffe gemeint. Sorry wenn das irreführend ausgedrückt war.

    dot schrieb:

    Und Operationen auf einem bool oder int oder sonstwas sind im Allgemeinen ganz gewiss nicht atomar.

    Dass z.B. die Anweisung

    i++;
    

    aus mehreren Maschinenbefehlen besteht, die mitten in der Ausführung unterbrochen werden können, ist mir klar.
    Aber Keine Ahnung ob eine Zuweisung schon als Operation gilt oder nicht. Kann eine Zuweisung unterbrochen werden? Und was ist mit Zeigern? Wird eine Anweisung wie

    *i = 5;
    

    aufgeteilt in eine Dereferenzierung und eine Zuweisung oder ist das auch nur eine Maschinenanweisung, die nicht unterbrochen werden kann?

    dot schrieb:

    Ich glaub du hast eine grundlegend falsche Vorstellung davon, wofür solche atomaren Operationen gut sind. Es ist jedenfalls nicht so, dass man einfach für Alles diese Funktionen benutzt und der Code dann auf magische Weise threadsafe wird.

    Mag sein, dass ich da was falsch verstanden habe. Ich denke es ist so: Wenn mehrere Threads lesend und schreibend auf ein ganze struct zugreifen bzw. mehrere Variablen lesen/ändern wollen, muss ich natürlich synchronisieren, sonst bekommt ein lesender Thread möglicherwiese inkonsistente Daten wenn er während des Lesens von einem schreibenden Thread unterbrochen wird.

    Ist das soweit richtig?

    Aber ich wollte doch nur, dass mein Programm nicht abstürzt wenn zwei Threads gleichzeitig auf eine Variable zugreifen. Deshalb: Kann ein Thread unterbrochen werden, wenn er einen primitiven Datentyp liest? Wenn ja, dann muss ich das verhindern, wenn nein, dann nicht. Kann sowas überhaupt zu einem Absturz führen oder ist diese Befürchtung völliger Quatsch?



  • SchlechterInformatiker schrieb:

    Ich habe nie etwas von atomaren Datentypen geschrieben. Im Titel steht "Atomarer Zugriff auf primitive Datentypen" - damit sind Lese- und Schreibzugriffe gemeint. Sorry wenn das irreführend ausgedrückt war.

    Ich wollt es nur extra betonen. Die Antwort auf diese Frage lautet immer noch: Das kann man allgemein nicht sagen. Das hängt von allem möglichen ab, evtl. bis hin zu irgendwelchen Compilerflags.

    dot schrieb:

    Kann eine Zuweisung unterbrochen werden?

    Das kann man allgemein nicht sagen. Eine Zuweisung an einen int der richtig aligned ist (!) wird vermutlich meistens atomar sein. Aber bei einem long ist das schon überhaupt nichtmehr so sicher. Der könnte auf der jeweiligen Plattform z.B. zwei Worte haben...

    SchlechterInformatiker schrieb:

    Und was ist mit Zeigern? Wird eine Anweisung wie

    *i = 5;
    

    aufgeteilt in eine Dereferenzierung und eine Zuweisung oder ist das auch nur eine Maschinenanweisung, die nicht unterbrochen werden kann?

    Auch hier wieder: Hängt davon ab. Evtl. muss z.B. zuerst die Adresse gelesen werden...

    Das einzige was man dazu allgemein sagen kann ist: Von solchen Annahmen sollte man sich am besten einfach nicht abhängig machen.

    SchlechterInformatiker schrieb:

    Mag sein, dass ich da was falsch verstanden habe. Ich denke es ist so: Wenn mehrere Threads lesend und schreibend auf ein ganze struct zugreifen bzw. mehrere Variablen lesen/ändern wollen, muss ich natürlich synchronisieren, sonst bekommt ein lesender Thread möglicherwiese inkonsistente Daten wenn er während des Lesens von einem schreibenden Thread unterbrochen wird.

    Ist das soweit richtig?

    Ja.

    SchlechterInformatiker schrieb:

    Aber ich wollte doch nur, dass mein Programm nicht abstürzt wenn zwei Threads gleichzeitig auf eine Variable zugreifen.

    Das kann nicht passieren.

    SchlechterInformatiker schrieb:

    Deshalb: Kann ein Thread unterbrochen werden, wenn er einen primitiven Datentyp liest?

    Hängt davon ab, diese Frage lässt sich allgemein nicht beantworten. Inwiefern ist das denn ein Problem?

    SchlechterInformatiker schrieb:

    Kann sowas überhaupt zu einem Absturz führen oder ist diese Befürchtung völliger Quatsch?

    Wenn dein Programm abstürzt, dann weil es versucht mit kaputten Daten zu arbeiten. Allein nur weil zwei Threads gleichzeitig auf die selbe Speicherstelle schreiben oder von der selben Stelle lesen passiert ganz sicher nichts.



  • Hallo,

    dot meinte mich 😉

    diese Aussage ist ihm sauer aufgestossen

    Der boolean sollte eigentlich aber auch gehen, mindestens der sollte Atomar sein.

    Wenn man diesen Satz für sich alleine Betrachtet, dann hat dot natürlich Recht.

    Aber wir waren ja ganz klar bei

    while (running)
    {
      ...
    }
    

    Natürlich hätte ich besser "mindestens dieser Zugriff sollte Atomar sein" gesagt.

    Herzliche Grüsse
    Walter



  • dot schrieb:

    Die Aussage dass bool atomar wäre macht keinen Sinn. Und Operationen auf einem bool oder int oder sonstwas sind im Allgemeinen ganz gewiss nicht atomar.

    Im Prinzip richtig!

    Laut Intel gibt es "basic memory operations" die atomar sind. Leider können Hochsprachenbefehle aber aus mehreren Maschinenbefehlen bestehen.

    Wenn eine Konstante (z.B. true, false) per atomarer "basic memory operation" gelesen oder geschrieben wird, scheint das aber hier zu gehen.

    Bei INC, DEC und anderen ist jedoch die Verwendung von LOCK dokumentiert, woraus
    man schliesssen kann, das es notwendig ist sich den Datenbus exlusiv zu sichern.
    (Datenwort lesen, inkrementieren und zurückschreiben ist bei mehreren CPUs wohl
    nicht sicher ...)

    SchlechterInformatiker schrieb:

    Dass z.B. die Anweisung

    i++;
    

    aus mehreren Maschinenbefehlen besteht, die mitten in der Ausführung unterbrochen werden können, ist mir klar.

    Genau da liegt das Problem. i++ ist EIN Maschinenbefehl (inc), aber TROTZDEM
    NICHT atomar ...



  • Ok, und was ist denn nun mit Zuweisungen? Sind die atomar?
    Kann höchstens "nur" vorkommen, dass eben ein veralteter Wert gelesen wird weil ein lesender Thread unterbrochen wurde und inzwischen ein schreibender Thread einen neuen Wert geschrieben hat?

    Oder kann da sogar ein Programmabsturz vorkommen wenn ein Thread während des Zugriffs auf eine Variable unterbrochen wird (nicht dass ich das bisher hätte, will aber trotzdem sicher gehen und vorbeugen)?



  • dot schrieb:

    SchlechterInformatiker schrieb:

    Und was ist mit Zeigern? Wird eine Anweisung wie

    *i = 5;
    

    aufgeteilt in eine Dereferenzierung und eine Zuweisung oder ist das auch nur eine Maschinenanweisung, die nicht unterbrochen werden kann?

    Auch hier wieder: Hängt davon ab. Evtl. muss z.B. zuerst die Adresse gelesen werden...

    [/quote]

    Wo wir gerade dabei sind: Im zitierten Programming Guide ist übrigens nur die Rede von Speicherzugriffen. Es gibt Instruktionen, die haben sowohl Lese- als auch Schreibzugriffe. Natürlich wird der Prozessor nicht unterbrochen, wenn er mitten in einer Instruktion steckt. Deswegen heisst es aber noch lange nicht, dass sich in einer Mehrprozessorumgebung zeitlich ein anderer Prozessor zwischen die Speicherzugriffe schieben könnte.



  • merano schrieb:

    dot schrieb:

    Die Aussage dass bool atomar wäre macht keinen Sinn. Und Operationen auf einem bool oder int oder sonstwas sind im Allgemeinen ganz gewiss nicht atomar.

    Im Prinzip richtig!

    Laut Intel gibt es "basic memory operations" die atomar sind. Leider können Hochsprachenbefehle aber aus mehreren Maschinenbefehlen bestehen.

    Natürlich ist auf Maschinenebene ganz klar definiert was atomar ist und was nicht. Aber hier gehts um C++ und da ist das eben nicht definiert und man sollte daher auch keine Annahmen über solche Dinge treffen 😉



  • Aaah Thread-Safety! Ich war gerade dabei meinen letzten Post zu editieren...

    Können Programmabstürze vorkommen?


  • Mod

    [quote="SchlechterInformatiker"]Ok, und was ist denn nun mit Zuweisungen? Sind die atomar?

    Steht doch alles in dem posting von Merano:

    Guaranteed Atomic Operations
    The Intel486 processor (and newer processors since) guarantees that the following basic memory operations will always
    be carried out atomically:
    . Reading or writing a byte
    . Reading or writing a word aligned on a 16-bit boundary
    . Reading or writing a doubleword aligned on a 32-bit boundary
    The Pentium processor (and newer processors since) guarantees that the following
    additional memory operations will always be carried out atomically:
    . Reading or writing a quadword aligned on a 64-bit boundary
    . 16-bit accesses to uncached memory locations that fit within a 32-bit data bus
    The P6 family processors (and newer processors since) guarantee that the following
    additional memory operation will always be carried out atomically:
    . Unaligned 16-, 32-, and 64-bit accesses to cached memory that fit within a cache line

    [quote="SchlechterInformatiker"]
    Oder kann da sogar ein Programmabsturz vorkommen wenn ein Thread während des Zugriffs auf eine Variable unterbrochen wird (nicht dass ich das bisher hätte, will aber trotzdem sicher gehen und vorbeugen)?

    Wie denn das bitte?
    Wir reden hier doch von atomaren Operationen in dem Sinn wie es Mearon schreibt. Wie soll überhaupt so etwas einen Programmabsturz verursachen?



  • x86 schrieb:

    Natürlich wird der Prozessor nicht unterbrochen, wenn er mitten in einer Instruktion steckt. Deswegen heisst es aber noch lange nicht, dass sich in einer Mehrprozessorumgebung zeitlich ein anderer Prozessor zwischen die Speicherzugriffe schieben könnte.

    genau. 100 Punkte. (s.o.)



  • @Martin Richter: Weiß ich nicht... das frage ich mich auch. Bei atomaren Operationen natürlich nicht. Deiner Antwort entnehme ich, dass das nicht vorkommen kann. Aber was gilt als atomare Operation und was nicht?

    Bezüglich des Postings von Merano:
    Da steht "The Intel486 processor"... was ist wenn aber mein Programm auf einem AMD oder sonst was läuft?



  • Hallo dot,

    Aber hier gehts um C++

    Jetzt bin ich spitzfindig 😃

    Hier gehts ganz klar um MFC(Visual C++) und daher um Windows.

    Herzliche Grüsse
    Walter



  • Nur um es nochmal ganz klar und deutlich zu sagen: Es ist nicht definiert ob und unter welchen Umständen irgendwelche Operationen in C++ atomar sind oder nicht und daher kannst du dich nicht drauf verlassen. Period.
    Wenn du atomare Operationen brauchst, dann musst du dich entsprechender Primitive bedienen, wie z.B. die erwähnten Funktionen der WinAPI oder irgendwelche Compiler Intrinsics oder sonstwas. C++11 bietet auch atomics in der Standardlibrary, die sind nur noch nicht überall verfügbar.



  • weicher schrieb:

    Hier gehts ganz klar um MFC(Visual C++) und daher um Windows.

    Point taken. Das ändert aber nix.



  • Ok, solange mein Programm nicht abstürzt weil zwei Threads gleichzeitig auf eine Variable lesend/schreibend zugreifen, ist alles in Ordnung.

    Veraltete Werte machen mir nicht aus. Dann wird halt erst im nächsten Zyklus aktualisiert.

    Ansonsten synchronisiere ich.

    Danke!



  • SchlechterInformatiker schrieb:

    Bezüglich des Postings von Merano:
    Da steht "The Intel486 processor"... was ist wenn aber mein Programm auf einem AMD oder sonst was läuft?

    Ich glaube nicht, das es sich ein Hersteller leisten kann dazu NICHT kompatibel zu sein.

    Wenn du es genau wissen musst: Auch AMD gibt schöne References raus; ebenfalls kostenlos ...

    Was wäre denn sonstwas ?

    Wir sprechen hier konkret von Windows (genauer: MFC ... 🙂



  • merano schrieb:

    Was wäre denn sonstwas ?

    Windows läuft aber auf den verschiedensten Plattformen (x86, x64, IA64, ARM, ...)
    Und außerdem hängt es vom jeweiligen Code und davon was genau der Compiler draus macht ab. Selbst wenn man sich auf Windows, x86 und MSVC festlegt, kann man immer noch keine allgemeinen Aussagen über solche Dinge machen.



  • SchlechterInformatiker schrieb:

    Ok, solange mein Programm nicht abstürzt weil zwei Threads gleichzeitig auf eine Variable lesend/schreibend zugreifen, ist alles in Ordnung.!

    Ich glaube Du hast es immer noch nicht ganz verstanden. Ein Programm stürzt _niemals_ ab weil 2 oder mehr Threads gleichzeitig irgendwas tun. Durch das "gleichzeitige" tun können aber Daten korrumptiert werden, die dann zu Abstürzen führen. Hat dot aber schon geschrieben.

    Falls Du es nur falsch beschrieben hast und trotzdem das richtige meintest: Solche Spitzfindigkeiten sind bei Multithreading sehr wichtig. Du siehst ja selbst der Pfad der Gerechten (= was man tun darf und was nicht) ist sehr schmal.



  • SchlechterInformatiker schrieb:

    Ok, solange mein Programm nicht abstürzt weil zwei Threads gleichzeitig auf eine Variable lesend/schreibend zugreifen, ist alles in Ordnung.

    Wollte damit nur sagen dass mir jetzt klar ist, dass ein Programm wegen sowas nicht abstürzen kann. Und dass es wegen inkonsistenten Daten dennoch abstürzen kann ist eh klar.


Anmelden zum Antworten