pthread_cancel -
スレッドにキャンセル要求を送る
#include <pthread.h>
int pthread_cancel(pthread_t thread);
-pthread でコンパイルしてリンクする。
pthread_cancel()
関数は指定されたスレッド
thread にキャンセル要求
を送信する。対象のスレッドがキャンセル要求に反応するかどうか、いつ反応
するかは対象のスレッドの制御下にある
2 つの属性、cancelability
state と
typeにより決まる。
あるスレッドの cancelability state
は
pthread_setcancelstate(3) で
設定され、
enabled と
disabled のいずれとなる (
enabled が新しい
スレッドのデフォルト値である)。スレッドがキャンセルを無効にしていた場合、
キャンセル要求はそのスレッドがキャンセルを有効にするまでキューに入れら
れたままになる。スレッドがキャンセルを有効にしていた場合、
cancelability type
によって、いつキャンセルが発生するかが決まる。
スレッドのキャンセル種別
(cancelability type) は
pthread_setcanceltype(3)
で設定され、
asynchronous か
deferred
のいずれかとなる(
deferred
が新しいスレッドのデフォルト値である)。
非同期キャンセル (asynchronous
cancelability)
は、そのスレッドはいつで
もキャンセルされることを意味する
(通常はすぐにキャンセルされるが、
システムがそのことを保証しているわけではない)。遅延キャンセル
(deferred cancelability)
では、そのスレッドが
取り消しポイント
(cancellation point)
となっている関数を次に呼び出すまでキャンセルが
遅延される。取り消しポイントに設定されていたり設定
したりできる関数のリストは
pthreads(7)
に記載している。
キャンセル要求が実行されると、
thread
では以下のステップが
(この順序で)
行われる。
- 1.
- キャンセルクリーンアップハンドラーが
(push されたのと逆順で)
取り出され (pop
され)、呼び出される。
( pthread_cleanup_push(3) 参照)
- 2.
- スレッド固有データのデストラクタ
(destructor)
が呼び出される。
呼び出し順序は規定されていない。
( pthread_key_create(3) 参照)
- 3.
- スレッドが終了される。
( pthread_exit(3) 参照)
上記のステップは
pthread_cancel()
の呼び出しとは非同期に行われる。
pthread_cancel()
の返却ステータスは単にキャンセル要求が正常に
キューに入れられたかどうかを呼び出し元に示すだけのものである。
キャンセルされたスレッドが終了された後に、
pthread_join(3)
でそのスレッドを join
すると、
そのスレッドの終了ステータスとして
PTHREAD_CANCELED が得られる。
(スレッドの join
はキャンセルが完了したかを知る唯一の方法である)
成功すると、
pthread_cancel()
は 0 を返す。
エラーの場合、0
以外のエラー番号を返す。
- ESRCH
- ID が thread
のスレッドが見つからなかった。
この節で使用されている用語の説明については、
attributes(7) を参照。
インターフェース |
属性 |
値 |
pthread_cancel() |
Thread safety |
MT-Safe |
POSIX.1-2001, POSIX.1-2008.
Linux
では、キャンセルはシグナルを使って実装されている。NPTL
スレッド実装では、
最初のリアルタイムシグナル
(つまり、シグナル
32)がこのために使用される。
LinuxThreads
では、リアルタイムシグナルが利用可能な場合は2
番目のリアルタイム
シグナルが使用され、そうでない場合は
SIGUSR2 が使用される。
以下のプログラムは、スレッドを一つ作成してから、そのスレッドをキャンセルする。
メインスレッドはキャンセルされたスレッドをジョインし、
キャンセルされたスレッドの終了ステータスが
PTHREAD_CANCELED かどうかを
確認する。以下のシェルセッションはこのプログラムを実行した際の実行例である。
$ ./a.out
thread_func(): started; cancellation disabled
main(): sending cancellation request
thread_func(): about to enable cancellation
main(): thread was canceled
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
static void *
thread_func(void *ignored_argument)
{
int s;
/* Disable cancellation for a while, so that we don't
immediately react to a cancellation request */
s = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
if (s != 0)
handle_error_en(s, "pthread_setcancelstate");
printf("thread_func(): started; cancellation disabled\n");
sleep(5);
printf("thread_func(): about to enable cancellation\n");
s = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
if (s != 0)
handle_error_en(s, "pthread_setcancelstate");
/* sleep() is a cancellation point */
sleep(1000); /* Should get canceled while we sleep */
/* Should never get here */
printf("thread_func(): not canceled!\n");
return NULL;
}
int
main(void)
{
pthread_t thr;
void *res;
int s;
/* Start a thread and then send it a cancellation request */
s = pthread_create(&thr, NULL, &thread_func, NULL);
if (s != 0)
handle_error_en(s, "pthread_create");
sleep(2); /* Give thread a chance to get started */
printf("main(): sending cancellation request\n");
s = pthread_cancel(thr);
if (s != 0)
handle_error_en(s, "pthread_cancel");
/* Join with thread to see what its exit status was */
s = pthread_join(thr, &res);
if (s != 0)
handle_error_en(s, "pthread_join");
if (res == PTHREAD_CANCELED)
printf("main(): thread was canceled\n");
else
printf("main(): thread wasn't canceled (shouldn't happen!)\n");
exit(EXIT_SUCCESS);
}
pthread_cleanup_push(3),
pthread_create(3),
pthread_exit(3),
pthread_join(3),
pthread_key_create(3),
pthread_setcancelstate(3),
pthread_setcanceltype(3),
pthread_testcancel(3),
pthreads(7)
この man ページは Linux
man-pages
プロジェクトのリリース
5.10
の一部である。プロジェクトの説明とバグ報告に関する情報は
https://www.kernel.org/doc/man-pages/
に書かれている。