私はpthreadと待機状態を学んでいます。私が知る限り、典型的な待機スレッドは次のようになります。
pthread_mutex_lock(&m);
while(!condition)
pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);
理解できないのは、while(!condition)
を使用してスレッドをウェイクアップしても、pthread_cond_signal()
行が必要な理由です。
pthread_cond_broadcast()
を使用する場合、条件をテストする必要があることを理解できます。なぜなら、all待機中のスレッドで、そのうちの1つがミューテックスのロックを解除する前に条件を再び偽にできるからです(したがって、その時点で実行すべきではない別のウェイクアップされたスレッドに実行を転送します)。しかし、pthread_cond_signal()
を使用する場合は、oneスレッドだけでウェイクアップするため、条件は真でなければなりません。したがって、コードは次のようになります。
pthread_mutex_lock(&m);
pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);
発生する可能性のあるスプリアス信号について読みました。これが(そしてこれだけ)理由ですか?なぜ偽の単音が必要なのですか?または、私が得られない何かがありますか?
信号コードは次のようになります。
pthread_mutex_lock(&m);
condition = true;
pthread_cond_signal(&cond); // Should wake up *one* thread
pthread_mutex_unlock(&m);
Whileループにpthread_cond_waitを配置する必要がある本当の理由は、誤ったウェイクアップのためではありません。条件変数に誤ったウェイクアップがない場合でも、一般的なタイプのエラーをキャッチするにはループが必要です。どうして?複数のスレッドが同じ条件で待機する場合に何が起こるか考えてください:
Thread 1 Thread 2 Thread 3
check condition (fails)
(in cond_wait) unlock mutex
(in cond_wait) wait
lock mutex
set condition
signal condvar
unlock mutex
lock mutex
check condition (succeeds)
do stuff
unset condition
unlock mutex
(in cond_wait) wake up
(in cond_wait) lock mutex
<thread is awake, but condition
is unset>
ここでの問題は、待機する前にスレッドがミューテックスを解放しなければならないことであり、潜在的にそのスレッドが待っていたものを「盗む」ことができます。 1つのスレッドのみがその条件で待機できることが保証されていない限り、スレッドがウェイクアップするときに条件が有効であると想定するのは誤りです。
状態をチェックしないと仮定します。それから通常、次の悪いことが起こるのを避けることはできません(少なくとも、1行のコードでそれを避けることはできません):
Sender Receiver
locks mutex
sets condition
signals condvar, but nothing
is waiting so has no effect
releases mutex
locks mutex
waits. Forever.
もちろん、2番目のコード例では、これを回避できます。
pthread_mutex_lock(&m);
if (!condition) pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);
そうすると、たった1つのレシーバーしか存在しない場合、およびcond_signal
は、それを起動できる唯一のものであり、条件が設定されたときにのみ起動するため、ループは必要ありません。 nosは、2番目の「if」が正しくない理由をカバーしています。