6

これはスレッドセーフですか?

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

変数 x は、アトミックまたはロックを使用せずに 2 つのスレッドからアクセスされます。ただし、 への呼び出しは 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 に答える