2013-07-07 73 views

回答

11

是的,那个特别的代码片段是线程安全的;不需要屏障或锁。

这是事件的时间表相对于你的代码:

thread 1 
-------- 
    | 
    int x = 0; 
    (write 0 to x) 
    | 
    std::thread    thread 2 
    (start thread 2) --------> -------- 
    |       | 
    join();      x = 1; 
    (thread 1 suspended)   (write 1 to x) 
    .       | 
    .       thread 2 returns 
    .       | 
    (thread 1 resumes) <------- x 
    | 
    std::cout << x; 
    (read from x) 
    | 
    thread 1 returns 
    | 
    x 

正如你所看到的,在任何一点x由多于一个线程访问。实际上,正如你猜测的那样,使用join()有效地使所有对x的访问按顺序发生join()提供了同步来代替从锁获得的同步。

基本上,你拥有的是一个如何使用零并发多线程的例子。

当然,这仅仅是因为调用join(),这是在您提供的代码片段中创建线程后立即发生的。如果不是有这样的事情:

int x = 0; 
std::thread t([&]{ x = 1; }); 
std::cout << x; 
t.join(); // Move join() call here 

的时间表,而不是看起来可能是这样:

thread 1 
-------- 
    | 
    int x = 0; 
    (write 0 to x) 
    | 
    std::thread    thread 2 
    (start thread 2) --------> -------- 
    |       | 
    std::cout << x;    x = 1; 
    (read from x)    (write 1 to x) <-- PROBLEM! 
    |       | 
    join();      | 
    (thread 1 suspended)   | 
    .       | 
    .       thread 2 returns 
    .       | 
    (thread 1 resumes) <------- x 
    | 
    thread 1 returns 
    | 
    x 

改变的join()这样的顺序将引入的比赛。

+2

这是一个非常全面的说'是'的方式。 –

+1

我想我将从现在开始使用该图表样式来发布线程。 – Prime

+0

除非join()有一些特殊的保证,那么即使在join()和打印旧结果之后,主线程也可以使用x的缓存值,否? – mitchnull