30

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.

Royi Namir
  • 144,742
  • 138
  • 468
  • 792
  • this is a sililar link about volatileread http://stackoverflow.com/questions/349192/use-of-volatile-thread-volatileread-thread-volatilewrite-in-c-sharp – Sakthivel Feb 23 '13 at 10:20
  • @codebrain I already saw it.none of the answers answer my question. (when should I use each and why does it exist if volatile already does it. plus there is no a single code how to use it).try to search `volatileRead` with ctrl+f - you will find none except for the title. – Royi Namir Feb 23 '13 at 10:22
  • 4
    The `volatile` keyword only works on fields. You could use `VolatileRead` and `VolatileWrite` to get the same semantics for non-field memory locations shared by multiple threads, like a variable in a closure. – anton.burger Feb 24 '13 at 12:16
  • If you have two different questions, you should ask them separately. – svick Feb 24 '13 at 13:28
  • @svick you right. it's just they both are so close so I thought I might ask them ... but you right. – Royi Namir Feb 24 '13 at 13:33
  • ***...reads/writes (on other threads) which comes AFTER...*** I think this highlights a misunderstanding of the purpose of volatile. I'm no expert on this topic myself, but fences prevent reordering of operations on the *same* thread, and everything I've learned suggests that they don't ensure you see the *latest* update from other threads, so much as that you either see an entire group of *related* updates by the same thread, or none at all. – anton.burger Mar 01 '13 at 11:38
  • @shambulator _and everything I've learned suggests that they don't ensure you see the latest update from other threads_ ...... **well** , you are wrong. see here a simple example which demonstrates your mistake : http://i.stack.imgur.com/FzGFY.jpg ( http://www.albahari.com/threading/part4.aspx) The whole purpose of Volatile is that changes reflects on another threads. – Royi Namir Mar 01 '13 at 15:39
  • @RoyiNamir I love that book, and it makes my point for me :) The use of volatile there ensures that *if* B sees `complete == true`, then it is *also* guaranteed to see any writes made by A *before* it set `complete` (i.e. before the fence, because any such writes are not allowed to move after the fence). This is *not* the same as B seeing `complete == true` the instant that A sets it. – anton.burger Mar 01 '13 at 15:53
  • You clearly like this topic as much as I do :) so you've probably seen [this already, but it's](http://www.bluebytesoftware.com/blog/2008/06/13/VolatileReadsAndWritesAndTimeliness.aspx) worth linking to here. Note `The confusion is over the "ensures that one thread receives the most up-to-date value written by another thread" part. Technically this is somewhat-accurate, but is worded in a very funny and misleading way. To see why, let’s take a step back and consider what volatile actually means...` – anton.burger Mar 01 '13 at 16:02
  • @shambulator are you here? goto http://chat.stackoverflow.com/rooms/25382/room-for-royi-namir-and-shambulator – Royi Namir Mar 02 '13 at 13:56

4 Answers4

37

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.

Slugart
  • 4,535
  • 24
  • 32
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • 1
    I wasn't kidding when I said " couldn't find **any** example" ...:-)....but indeed it's very strange. not a single sample in google.can you please tell me from where I can download all the documentation ? – Royi Namir Feb 24 '13 at 14:43
  • It isn't clear what "documentation" you ask for. The Reference Source source code is available here: http://referencesource.microsoft.com/netframework.aspx – Hans Passant Feb 24 '13 at 15:30
  • 1
    Does the volatile keyword has the same acquire/release semantics of Volatile.Read() and Volatile.Write() accordingto C#? In Mono 4.x the behavior is different. – Petrakeas Jul 06 '16 at 13:04
  • 1
    [Volatile is evil](http://joeduffyblog.com/2010/12/04/sayonara-volatile/). – Hans Passant Jul 06 '16 at 13:10
  • Now in .Net Core 3.1, there is plenty of volatile reads and writes to be found. – Dennis19901 Jan 18 '21 at 12:03
8

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#.

aleroot
  • 71,077
  • 30
  • 176
  • 213
  • 1
    What do you mean by _fine grained control over the way fences_ ? **show me one thing that volatile wont be able to do while volatile read/write will** - now this will teach me. The author says also : _"for having more control over the way fences are applied to our code"_ and then **he stops** - without explaining. ( plus I already saw this article also...:-) ) – Royi Namir Feb 23 '13 at 10:27
  • _ write immediately_ is by default....no ? why there even a method for volatile write ? – Royi Namir Feb 23 '13 at 10:37
  • It's a matter of more control, with a volatile variable you can't decide do do only uncached read operation or immediate write operation, you are tied to do both without choice ... See the updated answer that should clarify a little bit more ... – aleroot Feb 23 '13 at 10:38
4

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

address is not an int. It is an int* (so it really is an address). The code is dereferencing the pointer and copying it to a local so that the barrier occurs after the dereference.

usr
  • 168,620
  • 35
  • 240
  • 369
  • `void Main() { int g=2; aaa(ref g); } public void aaa(ref int address) { Console.WriteLine ( address); //2 }` – Royi Namir Feb 23 '13 at 10:44
  • Returnning `address` will return the value. ( I didnt ask why the ref. I asked why the proxy assignment.) – Royi Namir Feb 23 '13 at 10:45
  • How would you write the memory barrier without a proxy assignment? The barrier must come after the dereferencing and before returning. The variable is placed in a register anyway so it has performance cost. – usr Feb 23 '13 at 11:02
  • sorry maybe i'm a bit rusty , but what's wrong with `public static int VolatileRead(ref int address) { MemoryBarrier(); return address; }` – Royi Namir Feb 23 '13 at 11:11
  • 4
    That you are reading the int after the memory barrier. Did you understand my remarks regarding address being a pointer to an int and not an int? Note that it is **ref** int, not int. – usr Feb 23 '13 at 12:13
1

To Elaborate more on aleroot's answer.

Volatile.Read and Volatile.Write are same as volatile modifier as Royi Namir's argument. But you can use them wisely.

For example if you declare a field with volatile modifier then every access to this field whether it is read or write operation it will be read from CPU Register which is not free, this is not required in most of cases and will be unnecessary performance hit if field is even have many read operation.

Think of scenario where you have private singleton variable is declared as volatile and is returned in property getter, once it is initialized you don't need to read it's root from CPU Register hence you can use Volatile.Read / Write until it's instance created, once created all read operation can be done as normal field otherwise it would be big performance hit.

Whereas you can use Volatile.Read or Volatile.Write on demand bases. Best uses is declare field without volatile modifier and use Volatile.Read or Volatile.Write when needed.

Rajnikant
  • 2,176
  • 24
  • 23