私は基本的に、それはこのようになり、std::condition_variable(lock,pred)
のVC++の実装に見てきました:std :: condition_variableで可能な競合状態ですか?
template<class _Predicate>
void wait(unique_lock<mutex>& _Lck, _Predicate _Pred)
{ // wait for signal and test predicate
while (!_Pred())
wait(_Lck);
}
基本的には、cond->_get_cv()->wait(cs);
(これらのすべてはしているが呼び出されますdo_wait
を呼び出す_Cnd_wait
を呼び出し裸wait
通話_Cnd_waitX
ファイルcond.c)。
cond->_get_cv()
Concurrency::details::stl_condition_variable_interface
を返します。私たちは、ファイルprimitives.h
に行けば
は、我々は、Windows 7と上記の下で、私たちは古き良きwin32のCONDITION_VARIABLE
、およびwait
通話__crtSleepConditionVariableSRW
を含むクラスstl_condition_variable_win7
を持っていることがわかります。
アセンブリのデバッグを少し行うと、__crtSleepConditionVariableSRW
は、SleepConditionVariableSRW
関数ポインタを抽出して呼び出します。
私の知る限り、win32 CONDITION_VARIABLE
はカーネルオブジェクトではなく、ユーザーモードのものです。したがって、あるスレッドがこの変数に通知し、スレッドが実際にスリープしていない場合、通知が失われ、タイムアウトに達するか、他のスレッドが通知するまでスレッドはスリープ状態を維持します。小さなプログラムが実際にそれを証明することができます - あなたが通知のポイントを見逃しても、あなたのスレッドは他のスレッドが通知してもスリープ状態のままです。
私の質問は次のようになります。
条件変数で1つのスレッドが待機し、述部がfalseを返します。次に、上で説明したコール全体が実行されます。その時、別のスレッドが環境を変更して述語が真を返すようにとが条件変数を通知します。私たちは元のスレッドで述語を渡しましたが、まだSleepConditionVariableSRW
には入りませんでした。コールチェーンが非常に長くなりました。
したがって、我々は条件変数とを通知しましたが、条件変数に置かれた述語は確かにtrueを返すでしょう(notifierが作ったので)、私たちは依然として永遠に条件変数をブロックしています。
これはどのように動作するのですか?それは起こるのを待っている醜い競争状態のように思えます。条件変数に通知し、述語がtrueを返す場合、スレッドはブロックを解除する必要があります。しかし、述語をチェックしてから眠るまでの間にぼやけていると、私たちは永遠にブロックされます。 std::condition_variable::wait
はアトミック関数ではありません。
標準はそれについて何と言っていますか?それは本当に競合状態ですか?
aha、私は "共有変数がアトミックであっても..."ということを忘れていました。これは私が心に留めていたものです。 –
@DavidHaim:これはcppreferenceのヒントです。スタンダードには何の言い方もない。 'std :: condition_variable'(一般に条件変数と同様に)は、待ちと通知との間の関係を作成し、mutexを保持します。そのような方法でmutexを取得する正当な理由があると想定されます。か否か。そのミューテックスと何をするかはあなたのビジネスです。条件変数が実際に行う唯一のことは、ミューテックスを解放し、待ち状態* atomically *に入ることです。 「条件」の部分は完全にあなた次第です。 – conio