sAn
sAn

Reputation: 33

Force memory ordering

If there are pointers "A" and "B", with a requirement such that any writes to "A" should be made visible before any writes to "B" are made visible. If I am not allowed to use locks and if I am not allowed to declare these variables as "volatile", will the following code guarantee that, the above requirement will be met?

volatile temp;

*A = value1;
temp = *A;

if (temp == value1) {
    *B = value2
}

Upvotes: 3

Views: 191

Answers (4)

Kirill Kobelev
Kirill Kobelev

Reputation: 10557

The answer is simple. You cannot. Reordering can happen because:

  • Compiler will decide to reorder (it is allowed to do so, although this depends on compiler flags, etc);
  • Processor will decide to reorder. If the the processor is complex enough it will definitely do so.

To force memory ordering you need synchronization. Unfortunately there are tons of approaches here. Each approach has its own pros and cons. Depending on your situation you need to pick some.

Upvotes: 2

nwellnhof
nwellnhof

Reputation: 33618

I think it would be perfectly legal for a C compiler to reorder your example code like this:

volatile temp;

old_b = *B;
*B = value2;    
*A = value1;
temp = *A;

if (temp != value1) {
    *B = old_b;
}

Something like that would probably be better:

volatile temp;

temp = value1;
*A = temp;
temp = value2;
*B = temp;

But even if you know that the store instruction for B appears after the store instruction for A, this still wouldn't guarantee that other threads "see" the modifications in that order. This will depend on cache synchronization and is basically unpredictable. You'll need memory barriers or a locking mechanism to make it work reliably.

Upvotes: 1

david.pfx
david.pfx

Reputation: 10868

No, it won't. And there is no way you can diddle around with volatile and simple C constructs to achieve it either. The compiler is free to reorder your code as long as your program works right (and anybody else be damned!)

So the question is: what other options can you call upon? For example, if the only requirement is that another task never sees updates out of order, you can effectively guarantee that by making any system call between setting A and B. Even a call to a library function in a distant memory location would probably do the job. All you really need to do is to exceed the longest possible pipeline. But that could take a while...

Which brings me to the question: how are you going to test this? And how time critical is it?

Probably need more info to really answer the question.

Upvotes: 0

abligh
abligh

Reputation: 25119

You will want to use memory barriers or fences: see http://en.wikipedia.org/wiki/Memory_barrier

In the Linux kernel you can use the rmb() or wmb() calls.

Under pthreads you can use pthread_barrier_wait(), though that doesn't appear to be in my pthreads manpages.

On MSVC, look at Force order of execution of C statements? - which also has some good general information.

If you find an 'atomic' library, that will normally include barrier functions.

Upvotes: 3

Related Questions