kazmax - Linux で自宅サーバー

pthread_cleanup_push - ライブラリコールの説明 - Linux コマンド集 一覧表

  1. 名前
  2. 書式
  3. 説明
  4. 返り値
  5. エラー
  6. 著者
  7. 関連項目

名前

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);