1

Two threads accesses a shared int, x. What problems can arise from instruction reordering etc.

Thread 1:

x = 1;

Thread 2:

obj.f(x);

What would change if x is declarared volatile?
What would change if Thread 1 and Thread 2 runs on different cores?

Tobias Furuholm
  • 4,727
  • 4
  • 30
  • 39

3 Answers3

3

Two threads accesses a shared int, x. What problems can arise from instruction reordering etc.

Without mutexes? Don't do that or you'll be risking nasal demons. :-) To be exact, anything can happen. It might even appear to work (as long as you're not relying on consistent values). But really don't do that.

What would change if x is declarared volatile?

Not much, or maybe the behaviour would be different but you'd still not get things like you'd want. Volatile variables are for handling things like memory-mapped devices, not tricking your way past CPU caches.

What would change if Thread 1 and Thread 2 runs on different cores?

The problems would get worse (and yet you might not see any differences immediately either). Without a mutex or semaphore, you won't be using any memory barriers; they're the key to making things work (along with a proper lock to stop one thread from reading or writing when the other is writing) and they're not at all part of standard C++. That's why you use proper thread primitives; they solve these awkward problems for you.

Be aware that testing is not guaranteed to pick up thread consistency problems; they're inherently close to race conditions, and what happens will often change depending on system load.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
2

volatile is not meant for thread synchronization in c++, but rather to avoid certain compiler optimizations (see: http://en.wikipedia.org/wiki/Volatile_variable )

If you need to control access to x, you need to use a mutex or an atomic.

EDIT: Here's a discussion on what happens when you're reading without a mutex, even with just an int - Is it safe to read an integer variable that's being concurrently modified without locking?

Community
  • 1
  • 1
Brian Roach
  • 76,169
  • 12
  • 136
  • 161
  • 1
    Atomic or mutex is the solution. But the question is what happens if I DON'T protect the variable? – Tobias Furuholm Apr 17 '10 at 17:35
  • You get undefined behavior. It really ends up being a platform specific issue as to what you'd end up seeing if you're reading from thread 2 at the *same time* that x is being modified. – Brian Roach Apr 17 '10 at 17:39
1

If you do not sync the threads, the value of x can change anytimes in the view of Thread 2.

Let's look at:

class A {
public:
   A() { x = 0; }
   void set() { x = 1; }
   int f() { return x + x%2; }
   int x;
};

Now if thread 1 calls set and thread 2 calls f, without synchronisation, the result of f is undefined. It may be 0 + 0%2 or 1 + 0%2 or 1 + 1%2.

And it does not matter on what or how many cores the threads run. The order of execution is not defined, when not using explicit thread syncronization.

Danvil
  • 22,240
  • 19
  • 65
  • 88
  • I guess you mean given that f takes the parameter as a reference - f(int& value)? If f is declared f(int value) x would be copied to the stack... – Tobias Furuholm Apr 17 '10 at 17:28
  • @Tobbe - No. He's trying to explain the value of x is unknown in thread 2 because there's no guarantee that it's been set to 1 yet. – Brian Roach Apr 17 '10 at 17:33
  • Ok, this is an example of a race condition. I actually meant what can go wrong during a single write (in thread 1) and single read (in thread 2). But maybe that wasn't very clear... – Tobias Furuholm Apr 17 '10 at 18:35