std::atomic<bool>とcompare_exchange_strongでdeadlockしてしまう。
マルチスレッドプログラミングを勉強するために、std::atomicを二つのスレッドでcompare_exchange_strongを用いて反転させる(すなわち、true->false, false->trueに変換する)コードを書いたのですが、何回か繰り返し実行するとdeadlock?してしまうこと場合があることに気づきました。atomic操作であるため、deadlockは発生しないはずですがなぜこのような挙動が発生するのでしょうか?
Visual Studio 2015 Communityで現象が発生しています。
現象が発生するコードです。
#include<atomic>
#include<thread>
#include<mutex>
#include<iostream>
std::atomic<bool> a_bool(false);
// a_boolを1E5回反転させる関数
// 結局は何もしないのと同じである。
void func()
{
for (int j = 0; j < 1E5; ++j)
{
//ここのifがあやしい?
if (a_bool.load(std::memory_order_acquire))
{
//a_bool.load = trueのため、true->falseへ書き換える
bool expected = true;
bool desired = false;
// a_boolを反転させる
// もし、a_boolがほかのthreadにより反転させられている場合は、
// compare_exchange_strongにより、falseが返り値となり、whileが継続する。
// 他のthreadが再度反転させるまでwhile loopで待ち続ける。
do {
// 書き換えに失敗した場合はexpected = falseに
// 書き換えられるため、trueに戻す。
// これにより、ほかのthreadがa_boolをtrueに戻すまで待つ。
expected = true;
} while (!a_bool.compare_exchange_strong(expected, desired));
}
else
{
//true branchの反対
bool expected = false;
bool desired = true;
do { expected = false; } while (!a_bool.compare_exchange_strong(expected, desired));
}
}
}
int main(int argc, char const* argv[])
{
std::thread t1(func);
std::thread t2(func);
t1.join();
t2.join();
std::cout << "a_bool: " << a_bool.load(std::memory_order_acquire) << std::endl;
return 0;
}
追記
以下のように書き換えると問題が発生しなくなります。
ということはwhile loopで問題が発生していることになります。
if(!a_bool.compare_exchange_strong(expected, desired))
{
j--;
}