Laden...

Was ist der Unterschied zwischen volatile und atomar?

Erstellt von Palladin007 vor 3 Jahren Letzter Beitrag vor 3 Jahren 1.414 Views
Hinweis von gfoidl vor 3 Jahren

Abgeteilt von Buch zu den .NET-Internas?

Palladin007 Themenstarter:in
2.078 Beiträge seit 2012
vor 3 Jahren
Was ist der Unterschied zwischen volatile und atomar?

Das Thema kam auf, als ich nachgelesen habe, das Variablen-Zugriffe scheinbar nicht ganz so atomar sind, wie erst gedacht - aus dem Grund gibt's ja volatile.
Das wusste ich auch vorher schon (war mir nur nicht ganz sicher), aber weil ich das nochmal genauer nach gelesen habe, wurde mir klar, wie wenig ich eigentlich über die Runtime weiß.

Daher der Plan, dass ich mich genauer einlese, ohne dass es ein konkretes Problem/Projekt/Ziel gibt.

T
2.219 Beiträge seit 2008
vor 3 Jahren

Hat auch nicht viel mit der Runtime als mehr mit den spezfizierten Datentypen zu tun.
Die grundlegenden Datentypen wie int, double, float sind in den meisten Programmiersprachen nicht atomar bzw. muss man dafür über andere Typen wie AtomicInteger oder durch volatile dafür sorgen.

Dann geht dein Problem aber auch mehr in Richtung von üblichen Threading Poblemen, die nicht primär an .NET liegen sondern an den zu grunde liegenden Konzepten der Datentypen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.806 Beiträge seit 2008
vor 3 Jahren

Hat auch nicht viel mit der Runtime als mehr mit den spezfizierten Datentypen zu tun.

Nein, im Fall von .NET hat das durchaus was mit der Runtime zutun. Aber das ist ja nun nicht Teil des Themas 😃
Bitte beim Buchthema bleiben, danke.

Von dem ich prinzipiell viel lerne im Sinne von .NET unter der Haube ist eben Stephen Toub.
Der ist auch recht aktiv in den .NET Blogs und Co.

.NET PFX Team Blog

6.911 Beiträge seit 2009
vor 3 Jahren

Hallo,

auch wenns in diesem (Unter-) Forum offtopic ist, sollte das nicht unkommentiert stehen bleiben, da es nicht richtig ist.

Sollte das weiterer Diskussion bedürfen, so können wir das auch abteilen.

Variablen-Zugriffe scheinbar nicht ganz so atomar sind, wie erst gedacht - aus dem Grund gibt's ja volatile.

Die grundlegenden Datentypen wie int, double, float sind in den meisten Programmiersprachen nicht atomar bzw. muss man dafür über andere Typen wie AtomicInteger oder durch volatile dafür sorgen. volatile hat mit "atomar" nichts zu tun. Das sind zwei verschiedene Dinge -- beide haben ihren Ursprung zwar im "Threading", aber sind dennoch grundverschieden.

volatile ist ein Modifizierer für die Sichtbarkeit der Variable.

"atomar" heißt hier dass der Wert unteilbar (~ Atom) geschrieben / gelesen wird, ohne dass "torn writes / reads" zugelassen werden.
Typen deren Größe der Wortgröße der CPU entspricht werden immer atomar geschrieben / gelesen. sizeof(T) == Wortgröße <=> atomar.
D.h. bei x86 ist int, float atomar. Bei x64 ist double auch atomar.
Referenzen sind -- per Konstruktion -- ebenfalls immer atomar.
Größere Werttypen als Wortgröße der CPU brauchen besondere Behandlung, damit sie atomar verwendet werden können (z.B. durch Interlocked).

So nebenbei: das ist auch der Grund warum Span<T> nur "stack-only" ist, da es ohne Laufzeiteinbußen sonst nicht möglich ist atomare Vorgänge damit abzubilden. Da es eben nur auf dem Stack gestattet ist, gibt es kein Problem mit nebenläufigen Zugriffen.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

Palladin007 Themenstarter:in
2.078 Beiträge seit 2012
vor 3 Jahren

Das sind so Details, die ich mir von so einer Lektüre erhofft hätte - auch wenn sich das in diesem Fall nicht ausschließlich auf .NET bezieht, ist es trotzdem für .NET relevant und wichtig.

Danke für die Aufklärung 😃

4.931 Beiträge seit 2008
vor 3 Jahren

Hallo gfoidl,

volatile hat mit "atomar" nichts zu tun. Das sind zwei verschiedene Dinge -- beide haben ihren Ursprung zwar im "Threading", aber sind dennoch grundverschieden.

volatile ist ein Modifizierer für die Sichtbarkeit der Variable.

Das stimmt m.E. so aber auch nicht, denn volatile kann eben nur auf "atomare" Datentypen angewendet werden: volatile bzw. Volatile fields.
Und mit Sichtbarkeit auch nicht, sondern ob der Compiler bzw. das Runtime-System intern die Befehle neu anordnen oder Lese-/Schreibvorgänge eliminieren darf.

6.911 Beiträge seit 2009
vor 3 Jahren

Hallo Th69,

Und mit Sichtbarkeit auch nicht

Entsprechend dem Speichermodell (memory model) der CPU / Threads geht es bei volatile genau um die Sichtbarkeit (der Werte).
Z.B. dass der Wert nicht in einem Register gehalten werden darf, und somit "unsichtbar" für andere Threads ist, sondern "sichtbar" im Speicher sein muss. Mit "Speicher" sind hier auch allfällige Cache-Hierarchien gemeint und da geht es erst recht um die Sichtbarkeit (der Änderungen).
Zusätzlich wird beim Lesen ein "acquire fence" und ein "release fence" beim Schreiben gesetzt, so dass andere Lese-/Schreibvorgänge in Bezug auf den "fence" nicht umgeordnet werden dürfen. Auch dabei geht es um die Sichtbarkeit.
(Anm.: die "fences" sind auch Begriffe aus dem Speichermodell).

Vllt. hätte ich in der vorigen Antwort bei Sichtbarkeit den Bezug zum Speichermodell explizit herstellen sollen, denn mit Sichtbarkeit kann auch mehr gemeint sein (wie public, private, etc.) und somit hast du (in dieser Hinsicht) recht 😉

der Compiler bzw. das Runtime-System

Auch die CPU ist dabei betroffen.
Der/die Compiler dürfen beim Optimieren den Code nur so verändern, dass die "fences" von volatile erhalten bleiben.
Die Runtime / Execution Engine / VM müssen auch die "fences" erhalten lassen.
Die CPU muss dafür sorgen, dass in Bezug auf die "fences" die Sichtbarkeit des Speicherbereichs gegeben ist und darf keine Pipeline-Optimierungen vornehmen welche eine "fence" verletzen würden.

Intel x84/x64 ist hier von Haus aus eher streng ("strong memory model"), aber z.B. Arm-Prozessoren sind hier sehr locker ("weak memory model"). Daher ist für plattformübergreifenden Code und Threading die Kenntnis der Speichermodelle -- zu einem bestimmten Grade -- nicht ganz unwesentlich.

Einschub:
Kestrel (ein Server von ASP.NET Core) lief anfänglich nur auf x86*. Da in der Cloud immer mehr Arm64-CPUs Einzug halten, gab es folglich den Wunsch dass Kestrel auch Arm64 unterstützt. Wie sich jeder vorstellen kann sind Webserver sehr nebenläufig und parallelisiert. Ein großer Punkt für die Unterstützung von Arm64 war das "weak memory Model" und die korrekte Handhabung der Speicherzugriffen.
Neben ausführlichen Reviews für die Pull Requests werden zur Überprüfung auch jede Menge "Fuzz Tests" durchgeführt, denn gerade bei "Threading" ist nur durch "Hinschauen" nciht so einfach potentielle Fallstricke erkennen zu können.

* wird nur x86 angegeben, so sind Intel kompatible 32-/64-bit Systeme gemeint.
Andernfalls wird explizit von x86 und x64 od. Arm64 / Arm32, etc. gesprochen.

volatile kann eben nur auf "atomare" Datentypen angewendet

Danke dass du das ergänzt, ist aber auch nicht ganz korrekt / präzise (obwohl ich deine Intention dahinter sehr wohl verstehe).

volatile für Datentypen die größer als die Wortbreite der CPU sind machen keinen Sinn, da so das Prinzip von volatile nicht umgesetzt werden kann.

Dass der C#-Compiler hier long, double ausnimmt, liegt darin begründet dass .NET Anwendung plattformunabhängig laufen sollen, d.h. sowohl auf x86 und x64 und auf 32-bit Systemen (x86) sind diese beiden Datentypen nicht atomar.

Daher auch das "fast" oben, denn auf x64 sind double und long atomare Datentypen, dennoch kann volatile nicht darauf angewandt werden.
Gleiches gilt für atomare Werttypen auf die volatile nicht angewandt werden kann. Z.B.


public struct Foo
{
    public int A;
}

ist perfekt atomar, dennoch geht volatile nicht.

Als ich meine Antwort verfasste sah ich "atomar" nur in Bezug auf das von mir Zitierte.
Da sehe ich diesen Punkt immer noch als passend an, aber allgemein gesehen ist dieser Punkt zu unpräzise.

Ich bin immer wieder froh, dass es ein Forum gibt welches solche unpräzisen Punkte aufgreift 😃

Hallo Palladin007,

Das sind so Details, die ich mir von so einer Lektüre erhofft hätte

Wenn du einen Punkt hast der dich interessiert, so kannst du ja eine Frage im Forum stellen. Irgendwer wird schon eine Antwort schreiben... 😉

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

Palladin007 Themenstarter:in
2.078 Beiträge seit 2012
vor 3 Jahren

Danke für die ausführliche Aufklärung - hast Du Lust, ein Buch zu schreiben? 😄

Wenn du einen Punkt hast der dich interessiert, so kannst du ja eine Frage im Forum stellen.

Dann wäre ich nur noch mit Fragen stellen beschäftigt und würde das Forum im Alleingang füllen 😄

Ich hatte gehofft, ein Buch zu finden, in dem ich z.B. Abends ohne PC etwas lesen und so mein Allgemeinwissen etwas spezifischer ausweiten kann. Mir ist klar, dass ich dadurch nicht zum Experten werde, aber es kann schon viel ausmachen, einige Begriffe schon mal gehört/gelesen zu haben.

W
955 Beiträge seit 2010
vor 3 Jahren

Na das ist ja nun nicht schwer sich ein paar Blogs zu merken und jeden Abend mal ein Artikel zu lesen oder ein C#-Keyword nachzulesen oder ein Kapitel aus der C#-language spec wenn man sich durch trockenes Brot fräsen will ...

6.911 Beiträge seit 2009
vor 3 Jahren

Hallo Palladin007,

dazu hab ich (leider) keine Muße / Zeit 😉
Irgendwie interessant wäre es aber ein Buch der Art "Perlen von myCSharp.de" (o.ä.) zu erstellen, denn hier im Forum gibt es schon sehr viele gute tiefgründige Beiträge, die z.T. auch zeitlos sind.

Dann wäre ich nur noch mit Fragen stellen beschäftigt und würde das Forum im Alleingang füllen 😄

Warum auch nicht?

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"