Is a memory barrier required if a second thread wa

2019-01-29 12:49发布

问题:

Suppose that thread Alpha is writing to variable A without locking. A second thread Beta is waiting for Alpha to terminate, then reads the variable A in turn.

Is it possible that the contents of A will not be fresh? Can memory writes be delayed beyond the thread lifetime? Won't the standard mechanism of waiting for thread Alpha termination implicitly work as a memory barrier?

UPDATE 1

Are there any examples of waiting which does not include a memory barrier?

回答1:

Almost certainly (the API used to wait for thread termination would need to use memory barriers for its own purposes), but I think for a definitive answer you'll need to talk about the specific threading API being used.

For example, posix makes such a guarantee for pthread_join(): https://stackoverflow.com/a/3208140/12711

And Win32 documents that it's synchronization APIs to wait on an object (for example, a thread handle) impose memory barriers: http://msdn.microsoft.com/en-us/library/ms686355.aspx



回答2:

This depends on what guarantees your threading library provides. In particular, pthread_join() is defined to be a memory barrier. In most cases thread joining will involve a memory barrier, but it is not inconceivable that this may not always be the case.



回答3:

(Assuming you’re referring to C#.)

If you mean Thread literally, then your answer depends on whether Thread.Join implicitly generates memory barriers (which, per the answers already given, it probably does).

However, if you mean that Alpha and Beta are user-defined tasks executed on a background thread (possibly from the thread pool), and that “waiting” refers to user-level synchronization between the two tasks, then it’s more likely that the data will not be fresh, unless a signaling construct or an explicit barrier is introduced.

Here is a trivial example:

public class Program
{
    static string A = "foo";
    static volatile bool isAlphaReady = false;

    static void Alpha()
    {
        A = "bar";
        isAlphaReady = true;
    }

    static void Beta()
    {
        while (!isAlphaReady)
            ;   // Wait by polling
        Console.WriteLine(A);
    }

    static void Main(string[] args)
    {
        new Thread(Alpha).Start();
        new Thread(Beta).Start();
        Console.ReadKey();
    }
}

Although it appears (intuitively) that Beta will always output "bar" as the value of A, this is not guaranteed on a multiprocessor system with weak synchronization behaviour (such as Itanium), in which case, "foo" may be output instead.