6

这是线程安全的吗?

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

变量 x 从两个线程访问,而不使用原子或锁。但是,对 x 的调用 join()强制对 x 的访问是顺序的。

这里需要内存屏障吗?

4

1 回答 1

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()将引入比赛。

于 2013-07-07T03:55:57.477 回答