17

I'm trying to understand the C# Volatile class.

As i read:

  • The Volatile.Write method forces the value in location to be written to at the point of the call. In addition, any earlier program-order loads and stores must occur before the call to Volatile.Write.

  • The Volatile.Read method forces the value in location to be read from at the point of the call. In addition, any later program-order loads and stores must occur after the call to Volatile.Read.

Is that means the in the case of:

internal sealed class ThreadsSharingData {    
    private Int32 m_flag = 0;
    private Int32 m_value = 0;
    // This method is executed by one thread
    public void Thread1() {        
        // Note: 5 must be written to m_value before 1 is written to m_flag
        m_value = 5;
        Volatile.Write(ref m_flag, 1);        
    }

    // This method is executed by another thread
    public void Thread2() {        
        // Note: m_value must be read after m_flag is read
        if (Volatile.Read(ref m_flag) == 1)
        Console.WriteLine(m_value);        
    }    
}

the cpu will wait for the commands before Volatile.Write(ref m_flag, 1); before starting to write to m_flag?

And how is that helps the threads synchronization?

No Idea For Name
  • 11,411
  • 10
  • 42
  • 70
  • 1
    It is only relevant on processors with a weak memory model, the kind where acquire and release semantics matter. There are few left but ARM cores. It is *not* a substitute for proper synchronization, writing thread-safe code without synchronization is a very advanced concept. Otherwise already covered well in [this question](http://stackoverflow.com/questions/15039188/volatile-vs-volatileread-write). – Hans Passant Jun 19 '14 at 14:14

2 Answers2

11

the cpu will wait for the commands before Volatile.Write(ref m_flag, 1); before starting to write to m_flag?

Eeeh, kinda. A better way to phrase this is: it's guaranteed that, if any other thread sees m_flag set to 1, they will also see m_value set to 5.

And how is that helps the threads synchronization?

I wouldn't say it helps with synchronization - but it does help with achieving correctness.

If you weren't using volatile reads/writes, it would be possible for the compiler/runtime/cpu to reorder the two instructions in the Thread1 method, and the program would be able to print either 0, 5 or nothing at all.

With the volatile reads/writes, the program will print either 5 or nothing at all, but never 0. Which is the intended behaviour.

dcastro
  • 66,540
  • 21
  • 145
  • 155
5

How does that help thread synchronization?

It does not help thread synchronization in the sense of setting the order in which their commands execute. It lets you ensure that a concurrent thread observes changes to values in memory in a specific order, in cases when a particular order is important for the logic of your program.

[Does] the CPU wait for the commands before Volatile.Write(ref m_flag, 1); before starting to write to m_flag?

No, the command to write to m_value has already executed. However, its results may not be visible outside the CPU's core - in particular, a thread running on a different core might read an old value from m_value after the command that wrote 5 to it has finished executing. This is because the new value may be in the cache of the CPU, not in the memory.

If you write

m_value = 5;
m_flag = 1;

instead of Volatile.Write(ref m_flag, 1) the other core may see the writes in a different order: first it would see that m_flag became 1, and after that it would see that m_value became 5. If your other thread uses the value of m_flag to judge the validity of m_value, the logic may be broken: for example, Thread2 may occasionally print zero.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523