Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't C# volatile protect write-read reordering?

According to this online book, the volatile keyword in C# does not protect against reordering Write operations followed by Read operations. It gives this example in which both a and b can end up being set to 0, despite x and y being volatile:

class IfYouThinkYouUnderstandVolatile
{
  volatile int x, y;
 
  void Test1()        // Executed on one thread
  {
    x = 1;            // Volatile write (release-fence)
    int a = y;        // Volatile read (acquire-fence)
    ...
  }
 
  void Test2()        // Executed on another thread
  {
    y = 1;            // Volatile write (release-fence)
    int b = x;        // Volatile read (acquire-fence)
    ...
  }
}

This seems to fit with what the specification says in 10.5.3:

A read of a volatile field is called a volatile read. A volatile read has “acquire semantics”; that is, it is guaranteed to occur prior to any references to memory that occur after it in the instruction sequence.

A write of a volatile field is called a volatile write. A volatile write has “release semantics”; that is, it is guaranteed to happen after any memory references prior to the write instruction in the instruction sequence.

What is the reason for this? Is there a use case in which we don't mind Write-Read operations being reordered?

like image 549
Eric Avatar asked Jul 31 '12 18:07

Eric


People also ask

Why there is no string in C?

There is no string type in C . You have to use char arrays. By the way your code will not work ,because the size of the array should allow for the whole array to fit in plus one additional zero terminating character.

Why is C not A or B?

Because C comes after B The reason why the language was named “C” by its creator was that it came after B language. Back then, Bell Labs already had a programming language called “B” at their disposal.

What does C++ have that C does not?

C++ was developed by Bjarne Stroustrup in 1979. C does no support polymorphism, encapsulation, and inheritance which means that C does not support object oriented programming. C++ supports polymorphism, encapsulation, and inheritance because it is an object oriented programming language.

Is C very difficult?

It is not hard to learn C. Just like any other skill, you will need patience and resilience to master coding using C. The programming language features 32 keywords for its syntax. This makes it a relatively simple coding language to learn.


3 Answers

Volatile does not guarantee reads and writes of independent volatile variables are not re-ordered, it only guarantees that reads get the most up-to-date value (non-cached). (reads and writes to a single variable are guaranteed to maintain order)

http://msdn.microsoft.com/en-us/library/x13ttww7%28v=vs.71%29.aspx

The system always reads the current value of a volatile object at the point it is requested, even if the previous instruction asked for a value from the same object. Also, the value of the object is written immediately on assignment.

The volatile modifier is usually used for a field that is accessed by multiple threads without using the lock statement to serialize access. Using the volatile modifier ensures that one thread retrieves the most up-to-date value written by another thread.

Whenever you have multiple dependent operations, you need to use some other synchronization mechanism. Usually use lock, it's easiest and only creates performance bottlenecks when abused or in very extreme situations.

like image 70
Samuel Neff Avatar answered Sep 29 '22 19:09

Samuel Neff


Preventing volatile write with volatile read reordering will be quite expensive on x86/x64 arch. That's because of the write optimization called store buffers. Java went this way and volatile writes in Java are effectively full memory barriers at CPU instructions level.

like image 32
OmariO Avatar answered Sep 29 '22 21:09

OmariO


Maybe too late to answer ... but I was looking around and saw this. Volatile-read is actually a call to a method similar to the following:

public static int VolatileRead(ref int address)
{
    int num = address;
    Thread.MemoryBarrier();
    return num;
}

And Volatile-write is like this:

public static int VolatileWrite(ref int address, int value)
{
    Thread.MemoryBarrier();
    adrdress = value;
}

The instruction MemoryBarrier(); is the one preventing from reordering.MemoryBarrier(); ensures that intructions before are executed before intructions after. When VW then VR, you will have:

Thread.MemoryBarrier();
adrdress = value; //this line may be reordered with the one bellow
int num = address;//this line may be reordered with the one above
Thread.MemoryBarrier();
return num;
like image 24
adPartage Avatar answered Sep 29 '22 21:09

adPartage