Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between the volatile modifier and Volatile.Read/Write?

Do Volatile.Read and Volatile.Write have the exact same effect on a nonvolatile int that normal reads and assignments have on an int with the volatile modifier?

The motivation is to prevent the warning that volatile variables should not be passed via ref parameters to the Interlocked methods. (I understand that the program is correct in spite of the warning, but I'd rather not leave enigmatic pragmas in my code.)

//private volatile int suppressListChangedEvents;
private int suppressListChangedEvents;

public void SuppressListChangedEvents()
{
    Interlocked.Increment(ref suppressListChangedEvents);
}

public void UnsuppressListChangedEvents()
{
    if (Interlocked.Decrement(ref suppressListChangedEvents) < 0)
        throw new InvalidOperationException("Too many calls to unsuppress.");
}

protected override void OnListChanged(ListChangedEventArgs e)
{
    //if (suppressListChangedEvents != 0) return;
    if (Volatile.Read(ref suppressListChangedEvents) != 0) return;
    base.OnListChanged(e);
}

Likewise, I have a DirectX render thread pump that consumes commands using Interlocked.Exchange(ref command, null) and some commands are produced using direct assignment to the volatile command variable. Can I safely change that to Volatile.Write and remove the volatile modifier without introducing overhead?

EDIT: Definitive answer. Going forward, I'll shun the modifier and always explicitly access the variable via Volatile and Interlocked. That way the code has no ambiguity about the type of access; altering the variable declaration will not change the meaning of the code.

In a perfect world, I would make the volatile modifier useful by having the compiler deny the ability to directly reference or assign to the variable. That would force me to pass the reference to Volatile or Interlocked or a method that would itself use Volatile or Interlocked. I should get my hands on a copy of Roslyn.

like image 218
jnm2 Avatar asked Jul 15 '14 13:07

jnm2


1 Answers

There is no difference in your scenario; the only difference exists when talking about individual array elements:

In C#, using the volatile modifier on a field guarantees that every access to that field uses the Volatile.Read and Volatile.Write methods, but the volatile modifier cannot be applied to array elements. The Volatile.Read and Volatile.Write methods can be used on array elements.

So, as long as you are absolutely sure that you have caught all usages of the fields in question, you can safely change the blanket volatile to explicit volatile reads/writes.

like image 185
Jon Avatar answered Oct 04 '22 20:10

Jon