POS44-C. シグナルを使ってスレッドを終了しない
ハンドラが用意されていないシグナルを送信してスレッドを強制終了させてはならない。なぜなら、個々のスレッドではなくプロセス全体を強制終了させてしまうからである。このルールは「SIG02-C. 標準的な機能を実装する際はシグナルの使用を避ける」の具体例である。
POSIX システムでは、マルチスレッドプログラムにおける signal()
関数の使用はルール「CON37-C. マルチスレッドプログラムで signal() を呼び出さない」の例外事項 CON37-EX0 に該当する。
違反コード
次のコードは、pthread_kill()
関数を使って作成したスレッドに SIGTERM
シグナルを送っている。スレッドはシグナルを受け取り、プロセス全体が終了させられる。
void func(void *foo) {
/* スレッドの実行 */
}
int main(void) {
int result;
pthread_t thread;
if ((result = pthread_create(&thread, NULL, func, 0)) != 0) {
/* エラー処理 */
}
if ((result = pthread_kill(thread, SIGTERM)) != 0) {
/* エラー処理 */
}
/* プロセスは pthread_kill() で終了するためこのポイントには到達しない */
return 0;
}
適合コード
次の適合コード例では、pthread_cancel()
関数を使ってスレッドを終了させている。スレッドは、キャンセルポイントに達するまで実行を続ける。キャンセルポイントになる関数の一覧は「The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition」 [Open Group 2004] に記載されている。キャンセルの種類が非同期に設定されている場合、スレッドは即座に終了する。しかし POSIX で、非同期安全にキャンセルできることを要求されているのは、pthread_cancel()
、pthread_setcancelstate()
、pthread_setcanceltype()
のみである。他の POSIX 関数を非同期キャンセルを有効にして呼び出すアプリケーションは POSIX 準拠でない。それゆえ、「POS47-C. 非同期キャンセルが可能なスレッドを使用しない」に述べるように、非同期キャンセルは無効にすることが推奨される。
void func(void *foo) {
/* スレッドの実行 */
}
int main(void) {
int result;
pthread_t thread;
if ((result = pthread_create(&thread, NULL, func, 0)) != 0) {
/* エラー処理 */
}
if ((result = pthread_cancel(thread)) != 0) {
/* エラー処理 */
}
/* 実行を続ける */
return 0;
}
リスク評価
プロセスにシグナルを送信すると、プロセスの異常終了を引き起こす。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
POS44-C |
低 |
>中 |
低 |
P6 |
L2 |
参考資料
[OpenBSD] | signal() Man Page |
[MKS] | pthread_cancel() Man Page |
[Open Group 2004] | Threads Overview |
翻訳元
これは以下のページを翻訳したものです。
POS44-C. Do not use signals to terminate threads (revision 7)