これはスレッドセーフですか?
int x = 0;
std::thread([&]{ x = 1; }).join();
std::cout << x;
変数 x は、アトミックまたはロックを使用せずに 2 つのスレッドからアクセスされます。ただし、 への呼び出しは join()
、x へのアクセスを順次に強制します。
ここでメモリバリアが必要ですか?
これはスレッドセーフですか?
int x = 0;
std::thread([&]{ x = 1; }).join();
std::cout << x;
変数 x は、アトミックまたはロックを使用せずに 2 つのスレッドからアクセスされます。ただし、 への呼び出しは join()
、x へのアクセスを順次に強制します。
ここでメモリバリアが必要ですか?
はい、その特定のコード スニペットはスレッド セーフです。バリアやロックは必要ありません。
これは、コードに関するイベントのタイムラインです。
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()
種族が登場します。