スレッドが条件変数で待っている最中にシグナルが送られてきた場合の動作は、従来の規約では、割り込まれたシステムコールが EINTR エラーで戻るというものでした (ただし、プロセスは終了しないと仮定します)。
新たに注意すべき点は、cond_wait(3T) または cond_timedwait(3T) が復帰した時点で、mutex はロックし直されていることです。
Solaris では、スレッドが cond_wait() または cond_timedwait() でブロックされているとき、マスクされていないシグナルがスレッドに送られてくるとシグナルハンドラが呼び出され、その後 cond_wait() または cond_timedwait() は mutex をロックした状態で戻ります。
これは mutex がシグナルハンドラ内でロックされていることを意味します。シグナルハンドラは、スレッドの後処理をする必要があるかもしれないからです。このことは、Solaris オペレーティング環境 2.5 リリースでは成り立ちますが将来は変更される可能性があるので、この動作に依存しないでください。
POSIX スレッドでは、pthread_cond_wait(3T) はシグナルから復帰しますが、これはエラーではありません。pthread_cond_wait() は、ブロックが仮に解除されたことを示すため 0 を戻します。
例 5-4 で説明します。
int sig_catcher() { sigset_t set; void hdlr(); mutex_lock(&mut); sigemptyset(&set); sigaddset(&set, SIGINT); sigsetmask(SIG_UNBLOCK, &set, 0); if (cond_wait(&cond, &mut) == EINTR) { /* シグナルが発生、ロックは保持されている */ cleanup(); mutex_unlock(&mut); return(0); } normal_processing(); mutex_unlock(&mut); return(1); } void hdlr() { /* シグナルハンドラ内でロックは保持される */ ... } |
sig_catcher() が呼び出された時点では、すべてのスレッドで SIGINT シグナルがブロックされているものとします。さらに、sigaction(2) によって hdlr() が SIGINT シグナルのシグナルハンドラとして設定されているものとします。SIGINT シグナルをマスク解除して、cond_wait() で待ち状態になっているスレッドに SIGINT シグナルが送られてくると、スレッドは最初に mutex をロックし直し、その後 hdlr()を呼び出して、cond_wait() から EINTR エラーで戻ります。
sigaction() で SA_RESTART フラグを指定したとしても、ここでは意味がないことに注意してください。cond_wait(3T) はシステムコールではないため、自動的に再呼び出しされないからです。cond_wa でスレッドがブロックされているときにシグナルが送られてくると、cond_wait() は常に EINTR エラーで戻ります。なお、アプリケーションでは、割り込まれた cond_wait() が相互排他ロックを再獲得することに依存しないでください。この動作は、将来変更される可能性があります。