3

In C++ I'm taught to use volatile keyword for variable (myVar) that is used from different threads even under critical section. But for C# I read in MSDN this strange phrase: "The volatile modifier is usually used for a field that is accessed by multiple threads without using the lock statement to serialize access." Does this phrase mean that if I'm under lock then do not need to use volatile keyword? If yes, then one more question: may be I must do lock on exect this variable (myVar)?

Object a = new Object();
double i,k;
Thread1()
{
    lock(a)
    {
        i++;// using variable i.
        k++;// using variable k.
    }
}

Thread2 do the same. Is it safe that i and k not volatile, or I must do like that?:

lock(i)
{
    i++;// using variable i.
}
lock(k)
{
    k++;// using variable k.
}
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • Duplicate of http://stackoverflow.com/a/1682309/2958164 – Phillip Kinkade Dec 20 '13 at 02:20
  • start with [Eric Lippert's old blog](http://blogs.msdn.com/b/ericlippert/archive/2011/06/16/atomicity-volatility-and-immutability-are-different-part-three.aspx) – Mgetz Dec 20 '13 at 02:20
  • Learn [what C++'s `volatile` actually does](http://stackoverflow.com/questions/6866206/volatile-and-createthread/6866927#6866927). Very different from your understanding. Its usefulness is limited. – Cory Nelson Dec 20 '13 at 06:58
  • @CoryNelson: This is a good article as well: http://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/ – Eric Lippert Dec 20 '13 at 07:45
  • C# Tip: Don't lock on anything except objects specifically created to be used as locks (e.g., `private readonly object objlock = new object();`). [Like Jon Skeet](http://msmvps.com/blogs/jon_skeet/archive/2008/12/05/redesigning-system-object-java-lang-object.aspx), I really wish locking was only possible on lock objects; allowing locking on anything implies that it is OK. – Brian Dec 20 '13 at 14:18

3 Answers3

6

In C++ I'm taught to use volatile keyword for variable (myVar) that is used from different threads even under critical section

Whomever taught you this is not teaching you the whole story. Volatile in C++ makes no guarantees that reads or writes have acquire or release semantics! All volatile guarantees is that the compiler will not generate code that elides reads or does reads and writes out of order. Volatile alone is not enough to ensure correct semantics in multithreading unless your compiler makes some additional claim about what "volatile" means to it.

The volatile modifier is usually used for a field that is accessed by multiple threads without using the lock statement to serialize access." Does this phrase mean that if I'm under lock then do not need to use volatile keyword?

Correct. In C#, volatile does introduce acquire and release semantics by inserting the appropriate half fence. Since a lock introduces a full fence, volatile is unnecessary when reading a field in a lock.

may be I must do lock on exect this variable (myVar)?

All this code is so completely broken and wrong that it is impossible to answer the question. ++ is dangerous on doubles, making doubles volatile is not even legal in C#, and you can't lock on value types.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • "volatile is unnecessary when reading a field in a lock", I have always wondered: is this an implementation detail or is it in the spec? – markmnl Dec 20 '13 at 07:24
  • @markmnl: The C# specification carefully describes the relationship between volatile and lock. If this subject interests you then I recommend that you read the specification. – Eric Lippert Dec 20 '13 at 07:42
3

In standard C++ volatile has nothing to do with threads, although apparently Microsoft's compiler gives it some special meaning. For things like counters, use std::atomic<int>; no need for separate locks.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
0

Correct, in C# under lock you do not need to use volatile because using lock guarantees all threads see the most up-to-date value.

I agree with you, this is not clear from the MSDN documentation: lock is made out to only provide mutual exclusive access to a block of code, but in addition it also has other thread-safety featues such as ensuring every thread sees the same value, this in inherent in lock because it uses memory barriers.

Your second question is not possible - you have to lock on a reference type - supposing you did however, in both cases you operation is "thread-safe" provided all other reads and writes to the variables lock on the same instance, usually a more granule object is better so you do not have to make other threads wait when they want to update something else and have to acquire the same lock, but you may know these vars are always accessed together in which case a shared lock would be more efficient.

markmnl
  • 11,116
  • 8
  • 73
  • 109
  • So, in my example, is it safe to use lock(a) for both variables i and k? – user3121273 Dec 20 '13 at 03:32
  • your second thread needs to lock on the same object, i.e. lock(a){I++;k++}, then it is, yes. – markmnl Dec 20 '13 at 03:34
  • @user3121273 as a rule of thumb, always lock when accessing a var on the same instance as other locks, and you cannot go wrong, no need to worry about anything else, e.g. volatile... :) – markmnl Dec 20 '13 at 03:40
  • Thank you very much, Markmnl. Now I understand that in C++ I must use volatile even under critical section, but in C# it is not nessesary use volatile under lock. – user3121273 Dec 20 '13 at 03:46