5

Simplified the question to give a more clear representation of what I'm actually asking

I have two threads, call them A and B. They share one object of type Foo which has a field called Name and is stored in an array of type Foo[] at index 0. The threads will always access index 0 in a order which is guaranteed by the system already, so there is no race condition of thread B getting before thread A.

The order is this.

 // Thread A
 array[0].Name = "Jason";

 // Thread B
 string theName = array[0].Name

As I said this order is already guaranteed, there is no way for thread B to read the value before thread A

What I want to ensure is two things:

  1. Both threads get the latest object at index 0.
  2. Thread B always gets the latest value in the .Name field

Marking Name as volatile is not an option, as the real objects are a lot more complex and even have custom structs which can't even have the volatile attribute attached to them.

Now, satisfying 1 is easy (always getting the latest object), you can do a .VolatileRead:

 // Thread A
 Foo obj = (Foo)Thread.VolatileRead(ref array[0]);
 obj.Name = "Jason";

 // Thread B
 Foo obj = (Foo)Thread.VolatileRead(ref array[0]);
 string theName = obj.Name

Or you can insert a memory barrier:

 // Thread A
 array[0].Name = "Jason";
 Thread.MemoryBarrier();

 // Thread B
 Thread.MemoryBarrier();
 string theName = array[0].Name

So my question is: Is this enough to also satisfy condition 2? That I always get the latest value from the fields of the object I read out? If the object at index 0 has not changed, but the Name has. Will doing a VolatileRead or a MemoryBarrier on index 0 make sure all the fields IN the object at index 0 also get their latest values?

6
  • 1
    Why are you using arrays? Look at the System.Collections.Concurrent namespace. Commented Dec 18, 2011 at 11:03
  • Not using .NET4, to begin with. And the Concurrent stuff, as far as I know, only make guarantees for the content of the collections itself and not for the possible fields/properties of the objects in the collections. Commented Dec 18, 2011 at 11:08
  • I don't think volatile would guarantee what you think it would. Commented Dec 18, 2011 at 11:11
  • If there is no guarantee that the objects inserted into the array are threadsafe, I'd think you'd have to do some kind of check out check in system. I'd probably implement it by using one of the collections from the Concurrent namespace. Creating a new type which is IDisposable and generic, having a public T Value. Whenever a thread is then done with the item, it would dispose it, at which point you'd allow other threads to read it. Just a thought. Commented Dec 18, 2011 at 11:12
  • Another thought is to only allow threadsafe items into a custom collection. You'd just put a generic wrapper around a List<T> or T[] and have a constraint that T is IThreadSafe (which doesn't have any members, but stays as a reminder for you and other developers). Commented Dec 18, 2011 at 11:16

2 Answers 2

2

None of these solutions, lock or volatile will solve your problem. Because:

  1. volatile ensures that variables changed by one thread are visible immediately to other threads operating on the same data (i.e. they are not cached) and also that operations on that variable are not reordered. Not really what you need.
  2. lock ensures that the write / read do not occur simultaneously but does not guarantee their order. It depends which thread acquired the lock first, which is non-deterministic.

Therefore, if your flow is:

Thread A read Name
Thread A modify Name
Thread B read Name

exactly in that order, you will need to enforce it with an event (i.e. AutoresetEvent for example):

//Thread A
foo[0].Name = "John"; // write value
event.Set(); // signal B that write is completed

//Thread B
event.WaitOne(); // wait for signal
string name = foo[0].Name; // read value

This guarantees that thread B does not read the Name variable until A has modified it.

Edit: Ok, so you are sure that the above flow is respected. Since you are saying that you cannot declare the fields volatile, I recommend the use of Thread.MemoryBarrier() to introduce fences that enforce ordering:

//Thread A
foo[0].Name = "John"; // write value
Thread.MemoryBarrier();

//Thread B
Thread.MemoryBarrier();
string name = foo[0].Name; // read value

For more info, check this document: http://www.albahari.com/threading/part4.aspx

Sign up to request clarification or add additional context in comments.

15 Comments

This is not the problem, two threads can not access it at the same time. Ever. I think people are miss-understanding my question and I need to-rewrite it.
The access will always be sequential, but from two (or possibly more) different threads.
@thr: From this statement: "Now to be able to guarantee that Thread1 gets new value stored in the Name field of the Foo..." I understand that you need Thread1 to read Name only after Thread0 is done updating it.
Yeah I sort of think people miss-understood me. Thread1 will ALWAYS access the value of .Name after Thread0 has written it, this is guaranteed by the system already. What I'm worrying about is Thread1 being guaranteed to get the value that Thread0 wrote. There is no race-condition.
@thr: then all you need is volatile. See what I wrote in point 1 of my answer. I'll make an edit.
|
0

Locks will address the problem you have if I understand it correctly. This is because lock generates implicit (full) memory barriers around itself.

You can also use memory barrier explicitly using Thread.MemoryBarrier. Read more here. Memory barrier effect can be quite hard to notice on x86, but on more relaxed ordering system such as PPC it is often substantial.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.