pthread_cleanup_push - ライブラリコールの説明 - Linux コマンド集 一覧表
名前
pthread_cleanup_push, pthread_cleanup_pop, pthread_cleanup_push_defer_np, pthread_cleanup_pop_restore_np
- クリーンアップハンドラを登録および削除する
書式
#include <pthread.h>
void pthread_cleanup_push(void (*
routine
) (void *), void *
arg
);
void pthread_cleanup_pop(int
execute
);
void pthread_cleanup_push_defer_np(void (*
routine
) (void *), void *
arg
);
void pthread_cleanup_pop_restore_np(int
execute
);
説明
クリーンアップハンドラは、
pthread_exit
(3) が呼び出されたり、取り消しされたりして
スレッドが終了するときに呼び出される関数である。
クリーンアップハンドラは
スタック風の規則にならって登録および削除される。
クリーンアップハンドラの目的は、
スレッドが終了するときに保持しているかもしれない資源を
解放することである。
殊に、スレッドがロック中の mutex を保持したまま
終了したり取り消しされたりすると、
その mutex は永久にロックされたままで、
ほかのスレッドが正常に実行できなくなってしまう。
このことを防ぐ最もよい方法は、
mutex をロックする直前に、
mutex のロックを解除するための
クリーンアップハンドラを登録することである。
同じように、クリーンアップハンドラは
スレッドの終了時に
malloc
(3) で確保されたメモリブロックを解放したり
ファイルディスクリプターをクローズしたりするのに使用できる。
"pthread_cleanup_push"
は関数
"routine"
を引数
"arg"
とともにクリーンアップハンドラとして登録する。
この時点から
対応する
"pthread_cleanup_pop"
までの間、
そのスレッドが
pthread_exit
(3) または取り消しによって終了する時に、
関数
"routine"
が引数
"arg"
をともなって呼び出されるようになる。
終了する時点で複数のクリーンアップハンドラが有効になっている場合は、
クリーンアップハンドラは LIFO 順に呼び出される:
すなわち、最後に登録されたハンドラが最初に呼び出される。
"pthread_cleanup_pop"
は、最後に登録されたクリーンアップハンドラを削除する。
引数
"execute"
が 0 でない場合、
"pthread_cleanup_pop"
はハンドラを実行する。
すなわち、
関数
"routine"
を引数
"arg"
をともなって呼び出す。
引数
"execute"
が 0 の場合は、ハンドラが削除されるだけで、実行されることはない。
対応する
"pthread_cleanup_push"
と
"pthread_cleanup_pop"
の対は、同じ関数内の、
同じブロック階層になければならない。
実際、
"pthread_cleanup_push"
と
"pthread_cleanup_pop"
はマクロであり、
"pthread_cleanup_push"
のマクロ展開には
開き括弧
"{"
が含まれていて、それに対応する
閉じ括弧
"}"
は、対応する
"pthread_cleanup_pop"
のマクロ展開に含まれている。
"pthread_cleanup_push_defer_np"
は、
"pthread_cleanup_push"
と
pthread_setcanceltype
(3)を組み合わせた、ポータブルでない拡張である。
"pthread_cleanup_push"
とまったく同じようにクリーンアップハンドラを登録するが、
同時にその時点の取り消し型を保存し、
取り消し型を遅延 (deferred) に変更する。
これによって、
スレッドの取り消し型が非同期 (asynchronous) であっても
クリーンアップ機構が有効になることが保証される。
"pthread_cleanup_pop_restore_np"
は
"pthread_cleanup_push_defer_np"
によって登録されたはクリーンアップハンドラを削除し、
取り消し型を
"pthread_cleanup_push_defer_np"
が呼び出された時点の値に戻す。
"pthread_cleanup_push_defer_np"
と
"pthread_cleanup_pop_restore_np"
は対になっていなければならず、
ともに同じブロック階層になければならない。
pthread_cleanup_push_defer_np(routine, arg); pthread_cleanup_pop_defer_np(execute);
のような流れは機能的に次のものと同等 (だがよりコンパクトでより効率的) である。
{ int oldtype; pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); pthread_cleanup_push(routine, arg); ... pthread_cleanup_pop(execute); pthread_setcanceltype(oldtype, NULL); }
返り値
なし。
エラー
なし。
著者
Xavier Leroy <Xavier.Leroy@inria.fr>
関連項目
pthread_exit
(3),
pthread_cancel
(3),
pthread_setcanceltype
(3).
例
次の例は、 mutex
"mut"
をロック中にスレッドが取り消しされたら
ロックを解除するように、
mutex
"mut"
をロックする方法である:
pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut); pthread_mutex_lock(&mut); /* 何かをする */ pthread_mutex_unlock(&mut); pthread_cleanup_pop(0);
最後の 2 行は次のものと同等で、置き換えが可能である:
pthread_cleanup_pop(1);
上のコードは取り消し型が遅延 (deferred) である場合に限って
安全であることに注意すること (
pthread_setcanceltype
(3)を参照 ) 。
取り消し型が非同期 (asynchronous) の場合には、
スレッドの取り消しが
"pthread_cleanup_push"
と
"pthread_mutex_lock"
の間や、
"pthread_mutex_unlock"
と
"pthread_cleanup_pop"
の間で起こる可能性があり、
どちらの場合にもスレッドはカレントスレッドで
ロックしていない mutex をロック解除しようとしてしまう。
このことは非同期取り消しが使いにくいことの主な理由である。
上のコードが非同期取り消し型でも動作しなければならない場合、
mutex のロックおよびロック解除のために、
取り消し型を遅延 (deferred) に変更しなければならない:
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut); pthread_mutex_lock(&mut); /* do some work */ pthread_cleanup_pop(1); pthread_setcanceltype(oldtype, NULL);
上のコードは、ポータブルでない関数 "pthread_cleanup_push_defer_np" と "pthread_cleanup_pop_restore_np" を使うことで、よりコンパクトでより効率的な方法に書き直すことができる:
pthread_cleanup_push_restore_np(pthread_mutex_unlock, (void *) &mut); pthread_mutex_lock(&mut); /* do some work */ pthread_cleanup_pop_restore_np(1);