Is a memory fence required here?

Basically I have the following situation:

var tmp1 = new MyObject() { A = i, B = 2 };
// ** write barrier here??
this.Obj = tmp1;

      

Another thread can do things like this:

var tmp = this.Obj;
// ** read barrier here?? 
use(tmp.A);

      

Objects such as "Obj" are written only once, then read by multiple threads (multiple times).

I know Obj never has anywhere in both threads; I also don't care about "this.Obj" synchronization. What I really care about is that once I read the link tmp = Obj

, the content (eg A

and B

) is also valid.

My question is, do I need memory barriers (for example Thread.MemoryBarrier();

) in the above positions to make sure this is or is not always normal?


People seem to dislike this question.

My question comes from the following. I read on memory fences and they guarantee: (quote)

The processor executing the current thread cannot reorder instructions so that a memory access prior to a MemoryBarrier call occurs after a memory access following a MemoryBarrier call.

If you look at the code, the CPU / compiler will be able to rewrite the code:

var tmp1 = new MyObject();
tmp1.A = i;
tmp1.B = 2;
this.Obj = tmp1;

      

and worse:

var tmp1 = new MyObject();
this.Obj = tmp1;
tmp1.A = i;
tmp1.B = 2;

      

If another thread catches the latter case, it can read this.Obj

from memory as well A

and B

still have a default.

Note that this is not just a matter of what the compiler can change; it is also a matter of what the CPU can reorder.

In other words: (Thanks @MattBurland)

Is the object initializer guaranteed to run before tmp1 is assigned this.Obj

? Or do I have to use a memory fence to enforce this manually?

+3


source to share


1 answer


The C # spec only guarantees that the reordering cannot affect what the current stream sees. So it seems like the JIT is free to reorder the operations 2-4 below, since it doesn't affect the behavior of the producer thread:

  • Create a new MyObject

  • Assign i

    memberA

  • Assign 2

    memberB

  • Assign a new object this.Obj



So it seems like a barrier is required between steps 3 and 4.. Another option would be to do this.Obj

volatile

. This will ensure that no other reads or writes can be moved after being written to this.Obj

, while also providing the required ordering.

+1


source







All Articles