Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
volatile und Multithreading - Race bei i += 7
gunnag
myCSharp.de - Member



Dabei seit:
Beiträge: 3

Themenstarter:

volatile und Multithreading - Race bei i += 7

beantworten | zitieren | melden

Hallo zusammen,

es geht um C#, .NET und multithreading. Soweit ihc weiß sind lese und schreibzugriffe auf datentypen ≤ native int atomar und das schlüsselwort volatile gibt mir eine acquire und release semantic (also keinen full-fence).

Ich habe folgenden Ausschnitt und frage mich warum meine race-detektoren hier einen data race anzeigen im "get { ...}" und auf der code-zeile in thread 2? Ist das ein false positive?


private volatile int m_my_int;

//auf thread 1 ausgeführt
public int get_int
{
    get { return this.m_my_int; }
}


// auf thread 2 ausgeführt
this.m_my_int += 7;
private Nachricht | Beiträge des Benutzers
Spook
myCSharp.de - Member



Dabei seit:
Beiträge: 241
Herkunft: Esslingen a.N.

beantworten | zitieren | melden

Hallo gunnag,
Zitat von gunnag
das Schlüsselwort volatile gibt mir eine acquire und release semantic (also keinen full-fence).

Das volatile Schlüsselwort bewirkt, dass der Inhalt nicht gecacht, sondern bei jedem (lesenden) Zugriff neu aus dem Speicher in ein Register kopiert wird.

Eine genauere Beschreibung findest du hier:
volatile (C#-Referenz)

Ich frage mich eher, ob die Variable als volatile deklariert werden muss. Dies ist in diesem Fall vermutlich unsinnig, da der Property-getter die Variable eh nicht cachen kann und frisch aus dem Speicher auslesen muss. Solange nur Thread 2 die Variable ändert, kannst du volatile weglassen.

Grüße
spooky
private Nachricht | Beiträge des Benutzers
Taipi88
myCSharp.de - Member

Avatar #avatar-3220.jpg


Dabei seit:
Beiträge: 1.029
Herkunft: Mainz

beantworten | zitieren | melden

Hi,

die Frage kann ich zwar nicht sicher beantworten - aber mindestens das volatile muss man verwenden, da sonst der Wert ja auch durchaus in einem Register stecken kann. (Unwahrscheinlich - ja - aber möglich soweit ich weiß)

Folgende Erklärung fand ich super:
Volatility, Atomicity and Interlocking

LG
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Taipi88 am .
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 6.779
Herkunft: Waidring

beantworten | zitieren | melden

Hallo gunnag,

das Race kommt vom += von this.m_my_int += 7;

Das ist nicht atomar, denn was passiert hier:
  1. der Wert von m_my_int wird direkt aus dem RAM in ein (CPU-) Register gelesen (wegen volatile)
  2. der Wert im Register, dort wo jetzt also der Wert von m_my_int ist, wird um 7 erhöht
  3. der neue Wert im Register wird (wegen des C# MemoryModels*, hier nicht wegen volatile) in den RAM geschrieben

Wärhend dieser 3 Schritte kann also ein Race auftreten. Daher sollte hier eine Interlocked-Methode verwendet werden.

* C# hat ein "strong memory model" und somit ist jeder Schreibvorgang volatile by default. Das Verhalten von C# beim Schreiben wird auch als "strong volatile semantics" bezeichnet.
Zitat
meine race-detektoren
Welche verwendest du da?

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!"
private Nachricht | Beiträge des Benutzers
weismat
myCSharp.de - Member



Dabei seit:
Beiträge: 872
Herkunft: Frankfurt am Main

beantworten | zitieren | melden

Volatile Almost useless for multithread programming und atomicity, volatility and immutability are different
geben Dir mehr Anregungen.
Meine Erfahrungen mit Interlocked sind nicht so positiv - im Vergleich zu lock war es eher langsam...
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von weismat am .
private Nachricht | Beiträge des Benutzers
gunnag
myCSharp.de - Member



Dabei seit:
Beiträge: 3

Themenstarter:

beantworten | zitieren | melden

Danke Euch! Hilft schonmal weiter.

@gfoidl: Intel Inspector momentan
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4.176

beantworten | zitieren | melden

Generell zum Thema Multi-Threading kann ich Threading in C# (by Joseph Albahari) empfehlen.
Speziell: The volatile keyword

Ich würde, so wie gfoidl, hier auch die Interlocked-Operationen empfehlen.
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 6.779
Herkunft: Waidring

beantworten | zitieren | melden

Hallo weismat,
Zitat
im Vergleich zu lock war es eher langsam
Das kann schon sein, denn (speziell ab .net 4.0) wurde das optimiert, so dass eine Zeit lang "gespinnt" wird bevor zu einem richtigen lock per Monitor.Enter/Exit übergegangen wird.

Pauschal kann aber keine Aussage getroffen werden ob Interlocked od. lock schneller ist, denn es kommt immer auf die tatsächlich vorhandene Hardware und den ganeuen Anwendungsfall an.
Durch einen Profiler kann das aber getestet werden. Sonst sollte Code in erster Linie leserlich und nachvollziehbar geschrieben werden und "premature optimization is the root of all evil" (Donald E. Knuth) berücksichtigt werden. Gut bei Interlocked vs. lock wird der Code so od. nicht unleserlicher ;-)

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!"
private Nachricht | Beiträge des Benutzers
gunnag
myCSharp.de - Member



Dabei seit:
Beiträge: 3

Themenstarter:

beantworten | zitieren | melden

Hallo,

ich bin über folgendes gestolpert und würde gerne Eure Meinung dazu einholen:

hier steht: The C# Memory Model in Theory and Practice
Zitat
Ein Nachteil besteht darin, dass auch Typen, die normalerweise atomar gelesen und geschrieben werden (wie „int“), nicht atomar gelesen oder geschrieben werden können, wenn der Wert im Speicher nicht korrekt ausgerichtet ist. In C# ist die korrekte Ausrichtung von Werten normalerweise garantiert. Der Benutzer kann die Ausrichtung jedoch mithilfe der StructLayoutAttribute-Klasse überschreiben (bit.ly/Tqa0MZ).

ist das Korrekt? Das würde ja bedeuten, dass die primitive datatypes doch nicht atomar lesbar/schreibbar sind?
private Nachricht | Beiträge des Benutzers
inflames2k
myCSharp.de - Experte

Avatar #AARsmmPEUMee0tQa2JoB.png


Dabei seit:
Beiträge: 2.295

beantworten | zitieren | melden

Zitat von gunnag
ist das Korrekt? Das würde ja bedeuten, dass die primitive datatypes doch nicht atomar lesbar/schreibbar sind?

In der Regel wirst du für einen int keine Änderung an der Ausrichtung vornehmen. Allgemein habe ich sowas bisher nur selten gesehen (z.B. bei Komponenten zum Zugriff auf OPC-Server).

Klar ändert sich was am Verhalten von X, wenn du X änderst, solang du das aber nicht tust sollte der Zugriff weiterhin atomar sein.
Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager | Spielkartenbibliothek
private Nachricht | Beiträge des Benutzers
Spook
myCSharp.de - Member



Dabei seit:
Beiträge: 241
Herkunft: Esslingen a.N.

beantworten | zitieren | melden

In deinem Verlinkten Artikel steht ebenfalls:
Zitat
Die C# ECMA-Spezifikation garantiert, dass die folgenden Typen atomar geschrieben werden: Verweistypen, „bool“, „char“, „byte“, „sbyte“, „short“, „ushort“, „uint“, „int“ und „float“.

Ich vermute dass 64bit Datentypen in einem 64bit Prozess ebenfalls atomar geschrieben werden können.
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 6.779
Herkunft: Waidring

beantworten | zitieren | melden

Hallo Spook,

stimmt. Siehe dazu auch
Zitat von Interlocked.Read Method (Int64)(System.Threading)
The Read method is unnecessary on 64-bit systems, because 64-bit read operations are already atomic. On 32-bit systems, 64-bit read operations are not atomic unless performed using Read.

The Read method and the 64-bit overloads of the Increment, Decrement, and Add methods are truly atomic only on systems where a System.IntPtr is 64 bits long.

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!"
private Nachricht | Beiträge des Benutzers