pthread_cond_signalを呼び出す前にmutexをロックし、呼び出し後にmutextのロックを解除する必要があることをどこかで読みました。
Pthread_cond_signal()ルーチンは、条件変数を待機している別のスレッドにシグナルを送る(またはウェイクアップする)ために使用されます。 mutexがロックされた後に呼び出す必要があり、pthread_cond_wait()ルーチンを完了するためにmutexをロック解除する必要があります。
私の質問は:mutexをロックせずにpthread_cond_signalまたはpthread_cond_broadcastメソッドを呼び出しても大丈夫ではないですか?
条件と信号を変更するコードパスでミューテックスをロックしないと、ウェイクアップを失う可能性があります。このプロセスのペアを検討してください。
プロセスA:
_pthread_mutex_lock(&mutex);
while (condition == FALSE)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
_
プロセスB(不正解):
_condition = TRUE;
pthread_cond_signal(&cond);
_
次に、condition
がFALSE
で始まる命令の可能性のあるインターリーブを検討します。
_Process A Process B
pthread_mutex_lock(&mutex);
while (condition == FALSE)
condition = TRUE;
pthread_cond_signal(&cond);
pthread_cond_wait(&cond, &mutex);
_
condition
はTRUE
になりましたが、プロセスAは条件変数を待機し続けています-ウェイクアップ信号を逃しました。プロセスBを変更してミューテックスをロックする場合:
プロセスB(正しい):
_pthread_mutex_lock(&mutex);
condition = TRUE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
_
...その場合、上記は発生しません。ウェイクアップを見逃すことはありません。
(あなたはcanが実際にpthread_cond_signal()
をpthread_mutex_unlock()
の後に移動することに注意してください。スレッドの最適なスケジューリング、および条件自体の変更により、このコードパスですでにミューテックスをロックしている必要があります)。
このマニュアルによると:
pthread_cond_broadcast()
またはpthread_cond_signal()
関数は、現在mutexを所有しているかどうかにかかわらず、スレッドによって呼び出されます。pthread_cond_wait()
またはpthread_cond_timedwait()
を呼び出すスレッドは、待機中に条件変数に関連付けられています。ただし、予測可能なスケジューリング動作が必要な場合、そのミューテックスはpthread_cond_broadcast()
またはpthread_cond_signal()
を呼び出すスレッドによってロックされます。
予測可能なスケジューリング動作ステートメントの意味は、comp.programming.threadsのDave Butenhof( Programming with POSIX Threads の著者)によって説明されており、利用可能です- ここ 。
サンプルコードのcafは、最初にミューテックスをロックせずにcondition
を変更します。プロセスBがその変更中に単にmutexをロックし、pthread_cond_signal
を呼び出す前にmutexをまだロック解除した場合、問題はありません---それについて正しいですか?
私は直感的に、cafのpositionが正しいと信じています。mutexロックを所有せずにpthread_cond_signal
を呼び出すのは悪い考えです。しかし、cafの例は、実際にはこの位置を支持する証拠ではありません。ミューテックスを最初にロックしていない限り、ミューテックスによって保護されている共有状態を変更するのは悪い考えであるという、はるかに弱い(実際には自明の)立場を裏付ける証拠にすぎません。
pthread_cond_signal
に続いてpthread_mutex_unlock
を呼び出すと正しい動作が得られるが、pthread_mutex_unlock
に続いてpthread_cond_signal
を呼び出すと正しくない動作をするサンプルコードを提供できますか?