Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Volatile vs VolatileRead/Write?

I can't find any example of VolatileRead/write (try...) but still:

When should I use volatile vs VolatileRead?

AFAIK the whole purpose of volatile is to create half fences so:

  • For a READ operation, reads/writes (on other threads) which comes AFTER the current operation , won't pass before the fence. hence - we read the latest value.

Question #1

So why do I need the volatileRead? it seems that volatile already do the work.

Plus - in C# all writes are volatile (unlike say in Java), regardless of whether you write to a volatile or a non-volatile field - and so I ask: Why do I need the volatileWrite?

Question #2

This is the implementation for VolatileRead :

[MethodImpl(MethodImplOptions.NoInlining)] public static int VolatileRead(ref int address) {     int num = address;     MemoryBarrier();     return num; } 

Why the line int num = address; is there? they already have the address argument which is clearly holding the value.

like image 750
Royi Namir Avatar asked Feb 23 '13 09:02

Royi Namir


People also ask

When should I use volatile in C#?

The volatile keyword in C# is used to inform the JIT compiler that the value of the variable should never be cached because it might be changed by the operating system, the hardware, or a concurrently executing thread.

What is volatile read?

Reads the value of the specified field. On systems that require it, inserts a memory barrier that prevents the processor from reordering memory operations as follows: If a read or write appears after this method in the code, the processor cannot move it before this method.

Should we use volatile?

Yes, volatile must be used whenever you want a mutable variable to be accessed by multiple threads. It is not very common usecase because typically you need to perform more than a single atomic operation (e.g. check the variable state before modifying it), in which case you would use a synchronized block instead.

What does volatile mean in C#?

The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. The compiler, the runtime system, and even hardware may rearrange reads and writes to memory locations for performance reasons.


Video Answer


2 Answers

You should never use Thread.VolatileRead/Write(). It was a design mistake in .NET 1.1, it uses a full memory barrier. This was corrected in .NET 2.0, but they couldn't fix these methods anymore and had to add a new way to do it, provided by the System.Threading.Volatile class. Which is a class that the jitter is aware of, it replaces the methods at jit time with a version that's suitable for the specific processor type.

The comments in the source code for the Volatile class as available through the Reference Source tells the tale (edited to fit):

// Methods for accessing memory with volatile semantics.  These are preferred over  // Thread.VolatileRead and Thread.VolatileWrite, as these are implemented more // efficiently. // // (We cannot change the implementations of Thread.VolatileRead/VolatileWrite  // without breaking code that relies on their overly-strong ordering guarantees.) // // The actual implementations of these methods are typically supplied by the VM at  // JIT-time, because C# does not allow us to express a volatile read/write from/to  // a byref arg. See getILIntrinsicImplementationForVolatile() in jitinterface.cpp. 

And yes, you'll have trouble finding examples of its usage. The Reference Source is an excellent guide with megabytes of carefully written, tested and battle-scarred C# code that deals with threading. The number of times it uses VolatileRead/Write: zero.

Frankly, the .NET memory models are a mess with conflicting assumptions made by the CLR mm and C# mm with new rules added for ARM cores just recently. The weirdo semantics of the volatile keyword that means different things for different architectures is some evidence for that. Albeit that for a processor with a weak memory model you can typically assume that what the C# language spec says is accurate.

Do note that Joe Duffy has given up all hope and just flat out discourages all use of it. It is in general very unwise to assume that you can do better than the primitives provided by the language and framework. The Remarks section of the Volatile class bring the point home:

Under normal circumstances, the C# lock statement, the Visual Basic SyncLock statement, and the Monitor class provide the easiest and least error-prone way of synchronizing access to data, and the Lazy class provides a simple way to write lazy initialization code without directly using double-checked locking.

like image 128
Hans Passant Avatar answered Sep 21 '22 03:09

Hans Passant


When you need more fine grained control over the way fences are applied to the code can you can use the static Thread.VolatileRead or Thread.VolatileWrite .

Declaring a variable volatile means that the compiler doesn't cache it's value and always reads the field value, and when a write is performed the compiler writes assigned values immediately.

The two methods Thread.VolatileRead and Thread.VolatileWrite gives you the ability to have a finer grained control without declaring the variable as volatile, since you can decide when perform a volatile read operation and when a volatile write, without having the bound to read no cached and write immediately that you have when you declare the variale volatile, so in poor words you have more control and more freedom ...

VolatileRead() reads the latest version of a memory address, and VolatileWrite() writes to the address, making the address available to all threads. Using both VolatileRead() and VolatileWrite() consistently on a variable has the same effect as marking it as volatile.

Take a look at this blog post that explains by example the difference ...

Why the line int num = address; is there ? they already have the address argument which is clearly holding the value.

It is a defensive copy to avoid that something outside change the value while we are inside the method, the integer value is copied to the local variable to avoid an accidental change from outside.

Notes

Since in Visual Basic the volatile keyword doesn't exist you have the only choice of using consistently VolatileRead() and VolatileWrite() static methods to achieve the same effect of the volatile keyword in c#.

like image 30
aleroot Avatar answered Sep 22 '22 03:09

aleroot