5

If a thread A spawns another thread B with the single purpose of writing to a variable V and then waits for it to terminate, are memory-barriers required to ensure that subsequent reads of V on thread A are fresh? I'm unsure if there any implicit barriers in the termination / joining operations that make them redundant.

Here's an example:

public static T ExecuteWithCustomStackSize<T>
    (Func<T> func, int stackSize)
{
    T result = default(T);

    var thread = new Thread(
        () => 
                {
                    result = func();
                    Thread.MemoryBarrier(); // Required?
                }
        , stackSize);

    thread.Start();
    thread.Join();

    Thread.MemoryBarrier(); // Required?
    return result;
}

Are are either / both (or more) of the barriers in the above snippet required?

Ani
  • 111,048
  • 26
  • 262
  • 307
  • 4
    I doubt either memory barrier is required. If they were then Thread.Join would be pretty useless and a lot of people would be in trouble. Join waits till the thread finishes, which would include assigning the value to the variable. – Despertar Sep 16 '12 at 06:57
  • See this thread: http://stackoverflow.com/questions/6581848/memory-barrier-generators – Serve Laurijssen Jun 09 '13 at 12:05

3 Answers3

4

No, synchronization mechanisms generate implicit memory fences. All data modified by a thread will be visible after the thread is joined.

Tudor
  • 61,523
  • 12
  • 102
  • 142
  • 1
    Thanks for your answer. Any documentation to back this up? – Ani Sep 16 '12 at 15:15
  • 1
    @Ani: In this source: http://www.albahari.com/threading/part4.aspx (which everyone knows by now), they mention almost every synchronization mechanism as generating a fence. They don't explicitly mention `Join`, but since it puts the calling thread in the same state as `Monitor.Wait` for example, that's a strong hint it should also generate a fence. Furthermore, waiting on a `Task` is also mentioned. Although joining a thread is a bit different, I expect it to provide the same memory ordering guarantees. – Tudor Sep 16 '12 at 18:55
  • I did read that, but wasn't sure that was conclusive since, like you say, it didn't explicitly mention `Join`. – Ani Sep 17 '12 at 13:27
  • @Ani: Well I've been searching all over the web and everyone seems to omit `Thread.Join` from such discussions. I even tried looking over some old .NET library code released by MS, but `Join` goes into native code. I guess the only assurance I can give you is that: "it suspends the calling thread, so it _probably_ uses an event inside", "it should generate a fence otherwise the general semantics of join would be violated" and "in Java is generates a fence". :)) – Tudor Sep 19 '12 at 07:30
  • Thanks a lot for looking into this! – Ani Sep 19 '12 at 08:26
0

From the documentation it looks like they are not required -

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.

As you are blocking with join it is even more not necessary.

NiladriBose
  • 1,849
  • 2
  • 16
  • 31
0

You don't need the first memory barrier. You only need to call them before accessing data that has been modified in a separate thread. Since you aren't doing so inside 'thread', you don't need the call.

You can get rid of the second one if you plan on keeping the Join call. If you keep the second call, you can get rid of Join.

user123
  • 8,970
  • 2
  • 31
  • 52