pthread_atfork - ライブラリコールの説明 - Linux コマンド集 一覧表
名前
pthread_atfork - fork(2) の際に呼び出されるハンドラを登録する
書式
int pthread_atfork(void (*
prepare
)(void), void (*
parent
)(void), void (*
child
)(void));
説明
"pthread_atfork"
は
fork
(2) によって新しいプロセスが生成される際、その直前と直後に呼び出される
ハンドラ関数を登録する。
"prepare"
ハンドラは、新しいプロセスが生成される直前に親プロセスから
呼び出される。
"parent"
ハンドラは、
fork
(2) がリターンする直前に親プロセスから呼び出される。
"child"
ハンドラは
fork
(2) が返る直前に子プロセスから呼び出される。
prepare
,
"parent"
および
"child"
の三つのハンドラのうちの一つまたは複数に
NULL
を与えることができるが、これは対応する時点でいかなるハンドラをも
呼び出す必要がないことを意味する。
"pthread_atfork"
は複数のハンドラの組合せを登録するために複数回
呼び出すことが可能である。
fork
(2) の時点で複数の
"prepare"
ハンドラは LIFO 順で呼び出される(
pthread_atfork
で最後に加えられたものが
fork
の前に最初に呼び出される)。
他方、
"parent"
と
"child"
は FIFO 順で呼び出される
(最初に加えられたものが最初に呼び出される)。
pthread_atfork
の目的を理解するために、
fork
(2) は、現在ロック状態にある mutex も含めて、呼び出したスレッドのみの
メモリ空間全体を複製することを思い出そう。つまり、他のスレッドは
子プロセスでは実行されていないのである。従って、
fork
を呼び出したスレッド以外のスレッドによって mutex がロックされている
のならば、その mutex は子プロセスの中で永遠にロックされたままであり、
子プロセスの実行をブロックする可能性がある。
これを避けるためには、
"pthread_atfork"
で次のようなハンドラを登録すれば良いだろう:
"prepare"
ハンドラが大域的な mutex を(ロックする際の順序で)ロックし、
"parent"
と
"child"
がそれらを(逆の順に)アンロックする。
または、
"prepare"
と
"parent"
を
"NULL"
に設定し、
"child"
を大域的な mutex に対して
"pthread_mutex_init"
を呼び出す関数に設定しても良いだろう。
返り値
"pthread_atfork"
は成功すれば 0 を返し、エラーがあれば非ゼロのエラーコードを返す。
エラー
- "ENOMEM"
-
ハンドラを登録するのにメモリが足りない。
著者
Xavier Leroy <Xavier.Leroy@inria.fr>
関連項目
fork
(2),
pthread_mutex_lock
(3),
pthread_mutex_unlock
(3).
[訳注] glibc-linuxthreads の最新のドキュメントは Texinfo形式で提供されている。
以下は glibc-linuxthreads-2.3.1 の Texinfo ファイルからの引用である。
"pthread_atfork"
の目的を理解するために、
"fork"
が現在ロック状態にある mutex も含めたメモリ空間全体を、
しかし呼び出しスレッドだけを複製することを思い出してほしい。
つまり、他のスレッドは子プロセスでは実行されない。
mutex は
"fork"
の後は使うことができず、子プロセスで
"pthread_mutex_init"
を使って初期化されなければならない。
これは現在の実装の制限で、将来のバージョンでも存在するかもしれないし、
存在しないかもしれない。
これを避けるためには、
"pthread_atfork"
で次のようなハンドラを登録すればよい:
"prepare"
ハンドラで mutex を (ロックする際の順序で) ロックし、
"parent"
ハンドラで mutex をロック解除する。
"child"
ハンドラでは
"pthread_mutex_init"
を使用して mutex を初期化しなければならない。
条件変数などの他の同期オブジェクトについても同様である。
グローバル mutex を fork の前にロックすると、
他のスレッドはすべて、それらのグローバル mutex で保護される
コードのクリティカル領域から締め出される。したがって
"fork"
が親プロセスのアドレス空間のスナップショットを取ると、
そのスナップショットは有効で安定したデータをコピーする。
子プロセスで同期オブジェクトを初期化することで
親プロセスのスレッドサブシステムに由来するものが適切に清められることが保証される。
例えば、 mutex は獲得を待つスレッドの待ちキューを引き継ぐが、
この待ちキューは子プロセスでは意味を持たない。
mutex を初期化することでこのことに対処する。