9

条件変数は、notify()unlock_sleep()(mutexがロックされておらず、スレッドが1つのアトミックシーケンスの操作としてスリープするwait()の範囲内で使用される仮想関数呼び出し)に対して1つの順序を持​​つ必要があります。 std::condition_variable_any実装は、通常、内部で別のミューテックスを使用して、任意のlockablesでこれを達成するために内部unlock_sleep()notify()notify_one()またはnotify_all())の操作は、あなたがスレッドを危険にさらす互いに関してアトミックでない場合libC++ std :: condition_variable_anyの実装

(原子性を確保するとの上で寝るために)ミューテックスのロックを解除し、別のスレッドのシグナリングを行い、元のスレッドがスリープ状態になり、スリープ状態になることはありません。

私はのlibstdC++とのlibcのstd :: condition_variable_anyの++実装を読み、this code in the libc++ implementation

{lock_guard<mutex> __lx(*__mut_);} 
__cv_.notify_one(); 

内部ミューテックスがロックされ、その後すぐに信号操作の前にアンロックされて気づきました。私は上記の問題を危険にさらしていませんか?

libstdc++ seems to have gotten this right

+0

私は 'unlock_sleep()'に慣れていません。ドキュメントへのリンクを提供できますか?また、 'notify()'によって 'notify_one()'または 'notify_all()'のどちらかを意味しますか? –

+1

@MichaelBurr申し訳ありませんが、私はスリープ状態になり、ミューテックスを1つのアトミック操作としてロック解除するという一般的な操作を意味していました。 – Curious

答えて

1

C++ 11以降の標準明示的に "notify_onenotify_allの実行がアトミックでなければならない" と言います。だから、ある意味では、内部ミューテックスが、プラットフォームの基になる条件変数の通知コール(例えば、pthread_cond_signal())の下に保持されるべきだと思います。

しかし、私はlibC++実装がnotify_one()(またはnotify_all())を呼び出している間に、待機スレッドがロックに同期している通知スレッドがwait()(または2つのスレッド間の何らかの他の同期)に渡されないため、通知が失われる原因となります。とにかく通知するか待つかのどちらかを選択します。したがって、libC++の現在の実装で通知を見逃す可能性がある場合、libC++が呼び出されてプラットフォームの通知APIに内部ロックを保持するように変更された場合、通知が見逃される可能性があります。

だから私は、libcの++はnotify_one()/notify_any()の実装は、「十分なアトミック」であると言ってルール「かのように」を呼び出すことができると思います。

+0

> "libC++の現在の実装で通知が見逃される可能性がある場合は、libC++が内部ロックを保持するように変更され、プラットフォームの通知APIに内部ロックを保持すると、内部ロックが保持されている場合次に、スリープ状態になり、内部ミューテックスのロックを解除するという一連の流れはすべて不可能になります。内部ロックが保持されていた場合、内部ミューテックスのロックを解除してスリープ状態に入る途中で、通知がうまくいかないことがあります(これは私が尋ねる問題です) – Curious

+0

これらの2つのシナリオはどう違うのですか?スレッドWが実際に 'pthread_cond_wait()'を呼び出す前にスレッドNの 'notify_one()'が発生している(内部mutexをすでに解放しているため) **シナリオ2)** thread Nの 'notify_one()'呼び出しは、スレッドW 'wait()'が内部mutexを獲得する直前に実行されますか?私はいくつかの外部同期がなければ、APIのユーザーはこれらの2つの状況を区別できないと信じています。 –

+0

なぜ最初に 'notify_one()'にmutexを取得するのですか? – Curious

関連する問題