12

To implement a lock free code for multithreading application I used volatile variables, Theoretically: The volatile keyword is simply used to make sure that all threads see the most updated value of a volatile variable; so if thread A updates the variable value and thread B read that variable just after that update is happened it will see the most updated value that written recently from thread A. As I read in a C# 4.0 in a Nutshell book that this is incorrect because

applying volatile doesn’t prevent a write followed by a read from being swapped.

Could this problem being solved by putting Thread.MemoryBarrier() before every get of the volatile variable like:

private volatile bool _foo = false;

private void A()
{
    //…
    Thread.MemoryBarrier();
    if (_foo)
    {
        //do somthing
    }
}

private void B()
{
    //…
    _foo = true;
    //…
}

And if this solves the problem; consider we have a while loop that depend on that value at one of its conditions; is putting Thread.MemoryBarrier() before the while loop is a correct way to fix the issue? example:

private void A()
{
    Thread.MemoryBarrier();
    while (_someOtherConditions && _foo)
    {
        // do somthing.
    }
}

To be more accurate I want the _foo variable to give its most fresh value when any thread asking for it at any time; so if inserting Thread.MemoryBarrier() before calling the variable fixes the issue then could I use Foo property instead of _foo and do a Thread.MemoryBarrier() within the get of that property Like:

Foo
{
    get 
    {
        Thread.MemoryBarrier();
        return _foo;
    }
    set
    {
        _foo = value;
    }
}
CRABOLO
  • 8,605
  • 39
  • 41
  • 68
Jalal Said
  • 15,906
  • 7
  • 45
  • 68

5 Answers5

11

The "C# In a Nutshell" is correct, but its statement is moot. Why?

  • A 'write' followed by a 'read', withot 'volatile', is guaranteed to occur in program-order anyway if it effects logic within a single thread
  • The 'write' before a 'read' in a multi-threaded program is utterly pointless to worry about in your example.

Let's clarify. Take your original code:

private void A() 
{ 
    //… 
    if (_foo) 
    { 
        //do something 
    } 
}

What happens if the thread scheduler has already checked the _foo variable, but it gets suspended just before the //do something comment? Well, at that point your other thread could change the value of _foo, which means that all your volatiles and Thread.MemoryBarriers counted for nothing!!! If it is absolutely essential that the do_something be avoided if the value of _foo is false, then you have no choice but to use a lock.

However, if it is ok for the do something to be executing when suddenly _foo becomes false, then it means the volatile keyword was more than enough for your needs.

To be clear: all the responders who are telling you to use a memory barrier are incorrect or are providing overkill.

Brent Arias
  • 29,277
  • 40
  • 133
  • 234
  • 1
    thanks for your response; In my case I want to avoid do_something to be executed if the _foo was true as much as possible, but it is **not deadly critical**; but if I could make it more accurate with MemoryBarrier then **why not** use it with the volatile.. If the thread schedule suspend the thread after the _foo check "witch is possible" then the do_somthing will execute but at least we **reduce chances** that the _foo will be false at that time right? – Jalal Said Nov 25 '10 at 10:59
  • 2
    @Jalal: the `volatile` declaration already gaurantees, all by itself, that the variable will not be stored in a CPU register. It gaurantees direct memory reads and writes (which invalidates the cache of other processors on a multi-processor machine). Therefore the explicit memory barrier is unnecessary; the `volatile` is already accomplishing what you need. – Brent Arias Nov 25 '10 at 23:53
  • @BrentArias The MemoryBarrier *is* necessary because it is possible for the processor to update the value on one processor and not on the other so one thread reads an updated value and the other thread reads a stale value. – Anthony Aug 20 '13 at 14:35
5

The book is correct.
The CLR's memory model indicates that load and store operations may be reordered. This goes for volatile and non-volatile variables.

Declaring a variable as volatile only means that load operations will have acquire semantics, and store operations will have release semantics. Also, the compiler will avoid performing certain optimizations that relay on the fact that the variable is accessed in a serialized, single-threaded fashion (e.g. hoisting load/stores out of loops).

Using the volatile keyword alone doesn't create critical sections, and it doesn't cause threads to magically synchronize with each other.

You should be extremely careful when you write lock free code. There's nothing simple about it, and even the experts have trouble to get it right.
Whatever is the original problem you're trying to solve, it's likely that there's a much more reasonable way to do it.

Liran
  • 1,596
  • 1
  • 13
  • 11
  • @Liran: I knew that using the volatile alone doesn't creat critical sections nor causeing thread to be synchronize with each others.. I am just asking for the _foo variable to be must updated value when any thread ask for it at any time within lock free code. – Jalal Said Nov 25 '10 at 11:04
  • @Jalal, declaring the variable as volatile will guarantee that every load operation will read the most updated value of the variable (e.g. from the main memory instead of a register). You shouldn't spread memory barriers all over your code... doing so could have a major negative effect on performance. Again, if you're not just trying to play around and experiment with lock free code, and there's real, production code in the picture... I encourage you to find another solution. – Liran Nov 25 '10 at 13:22
  • @Liran; "declaring the variable as volatile will guarantee that every load operation will read the most updated value of the variable"; will as I understood from the book http://www.albahari.com/threading/part4.aspx that wirte follwed by read maybe not get the most updated value, and yes I am trying to experiment with lock free code; the question is: is it a big negative effect on performance of the application when do a `Thread.MemoryBarrier` before any get operation of the volatile variable,if it not I could put it in a property before any get of the variable. please see the question update – Jalal Said Nov 25 '10 at 13:42
  • 3
    @Jalal, a store operation, followed by a read operation may be reordered if there's no data dependency between the operations (e.g. a load to X, and store to Y). Make sure you understand the CLR's memory model. Joe Duffy did a good job summarizing the rules: http://www.bluebytesoftware.com/blog/2007/11/10/CLR20MemoryModel.aspx ... Also, the fact that you use a property has nothing to do with your code's thread safety. – Liran Nov 25 '10 at 13:58
  • @Liran: Thanks for the link I will read it for sure.. the property here is not for thread safety but it is for a freshness gurintee of the value when requested, If the value by using `volatile` is gurinteed to be alwayes fresh no matter of any thing then that is great, but if it not and no problem with `Thread.MemoryBarrier()` then way not use it in property? – Jalal Said Nov 25 '10 at 14:05
  • @Jalal, using a property doesn't effect the "freshness" of data in any way. A property just acts as a getter/setter method. If you don't need a full fence (Thread.MemoryBarrier), don't use it. You will just suffer from a needless performance penalty. Before continuing, make sure you understand what's a memory model, what are acquire/release semantics, fences etc. – Liran Nov 25 '10 at 14:28
1

In your second example, you would need to also put a Thread.MemoryBarrier(); inside the loop, to make sure you get the most recent value every time you check the loop condition.

David Gelhar
  • 27,873
  • 3
  • 67
  • 84
  • if this fixed the problem then putting Thread.MemoryBarrier() should be at the last line before close bracket of the while loop and before the call of the while loop.. – Jalal Said Nov 24 '10 at 17:41
  • 1
    @Jalal: I'm fairly certain that the explicit `MemoryBarrier` calls aren't required in these examples, so long as `_foo` is marked as `volatile`. (I'm no expert though; I'd probably just use a `lock`.) – LukeH Nov 24 '10 at 17:50
  • 3
    In this case: the use of Thread.MemoryBarrier, whether before, after, or both, is not achieving anything that volatile was not already achieving. – Brent Arias Nov 24 '10 at 19:03
1

Pulled from here...

class Foo
{
  int _answer;
  bool _complete;

  void A()
  {
    _answer = 123;
    Thread.MemoryBarrier();    // Barrier 1
    _complete = true;
    Thread.MemoryBarrier();    // Barrier 2
  }

  void B()
  {
    Thread.MemoryBarrier();    // Barrier 3
    if (_complete)
    {
      Thread.MemoryBarrier();       // Barrier 4
      Console.WriteLine (_answer);
    }
  }
}

Barriers 1 and 4 prevent this example from writing “0”. Barriers 2 and 3 provide a freshness guarantee: they ensure that if B ran after A, reading _complete would evaluate to true.

So if we go back to your looping example...this is how it should look...

private void A()
{
    Thread.MemoryBarrier();
    while (_someOtherConditions && _foo)
    {
        //do somthing
        Thread.MemoryBarrier();
    }
}
Aaron McIver
  • 24,527
  • 5
  • 59
  • 88
  • 1
    @ Aaron Thanks I check that link before it is at the same book "C# 4.0 in a Nutshell".. however if this fixed the problem then putting Thread.MemoryBarrier() should be at the last line before close bracket of the while loop. – Jalal Said Nov 24 '10 at 17:36
  • @Jalal It depends what your "do something" does, where the ThreadBarrier sits now affects your _someOtherconditions/_foo vars – Aaron McIver Nov 24 '10 at 17:41
  • 1
    @Aaron: If `_foo` is marked as `volatile` then I'm pretty sure that the explicit `MemoryBarrier` calls are unnecessary in these particular examples. (Pretty sure but not 100% sure, and if in doubt then I'd probably just use a `lock`.) – LukeH Nov 24 '10 at 17:45
  • 1
    @Aaron: because the loop has to change the conditions the barrier should be the last thing in the loop. – H H Nov 24 '10 at 17:56
  • @Henk Are you referring to the vars being used as the conditionals when you say "has to change conditions"? – Aaron McIver Nov 24 '10 at 18:04
  • 1
    Yes. And i formulated that wrong, the conditions change during the loop. So you want the barrier as late as possible. – H H Nov 24 '10 at 18:08
  • @Henk Makes sense. I still think it can depend on what "do something" does, as if it were something IO intensive you would not want to 'lock' that long, especially if it can be done outside the barrier without any consequences. Ran into issue before where overuse of lock was used and it became a problem... – Aaron McIver Nov 24 '10 at 18:12
  • 1
    "would not want to 'lock' that long" ??? A memoryBarrier call is a momentary thing, there is no locking or other state involved. It's more like flushing the pipes. – H H Nov 24 '10 at 18:16
  • @Henk Thanks for the correction, my misunderstanding of MemoryBarrier and it's comparison to lock – Aaron McIver Nov 24 '10 at 18:21
  • 2
    @Aaron: the link you provided deals with re-ordering issues. The poster's code example does not exhibit any re-ordering issues. All the poster needs is for the value of _foo to be read/written directly to memory instead of a register. The `volatile` keyword is sufficient for that all by itself. – Brent Arias Nov 24 '10 at 19:27
  • 1
    @Brent The link speaks about threading in general. It touches on MemoryBarrier and volatile alike, which is what the OP was questioning. – Aaron McIver Nov 24 '10 at 19:39
0

Microsoft's own words on memory barriers:

MemoryBarrier is required only on multiprocessor systems with weak memory ordering (for example, a system employing multiple Intel Itanium processors).

For most purposes, the C# lock statement, the Visual Basic SyncLock statement, or the Monitor class provide easier ways to synchronize data.

Bengie
  • 1,035
  • 5
  • 10