pthreadとスレッド終了時の動作について

PROCESS WARPでマルチスレッド対応、分散処理対応を行うためにpthreadの動作、特に終了処理について調査しました。 manを読みながら明記されていない部分をMacOSX環境でサンプルを作って確認しました。

  • exitで終了した場合、子スレッドも終了される。
    • atexitで登録した関数が終了前に呼び出される
    • 子スレッドでatexitで関数を登録しても、プロセス終了時に親スレッドで実行される
  • 子スレッドでexitを実行すると同一プロセスの全てのスレッドが終了する
    • pthread_clean_pushで登録した関数はexit時は実行されない
    • pthread_key_createで登録したデストラクタはexit時は実行されない
  • 子スレッドだけ終了するにはpthread_exitを利用する。
    • pthread_clean_pushで登録した関数がpthread_exitで実行される
    • pthread_key_createで登録したデストラクタが実行される
    • 関数が実行されるのはpthread_exitが呼び出されたか処理が終了したタイミングであり、joinのタイミングではない
  • 大元のスレッドでもpthread_exitを呼び出せる
    • pthread_clean_push、pthread_key_createで登録した関数が実行される
    • その後atexitで登録した関数が実行される
    • pthread_exit以降の処理は実行されない
    • 正常終了扱いになる
  • スレッドがmutexを保持したままpthread_exitやreturnで終了した場合、mutexはロック状態のままになる
    • 他のスレッドからthread_mutex_unlockを呼び出せばロックは解除できる
  • pthread_key_createで登録したデストラクタはpthread_setspecificでNULL以外を指定しているプロパティに対して呼び出される
    • returnでスレッド終了しても呼び出される
    • 大元のスレッドではreturn終了では呼び出されない

なので、

  • atexitで登録した関数のスタックはプロセスで1つだけ
  • pthread_key_createで登録したキー、デストラクタはプロセス内のスレッドで共通
  • pthread_setspecificで登録した値はスレッドごとに保持される
  • pthread_clean_pushで登録した関数はスレッドごとに保持される(スタックに積まれる)
  • exitで終了時または大元のスレッドがreturnする場合は、スレッドごとの終了処理はされない
  • pthread_exit呼び出し時はpthread_clean_push, pthread_key_createで登録した関数の順に呼び出す
  • pthread_exitを呼び出したのが大元のスレッドの場合は、その後にプロセスの正常終了処理を行う

という作りになっているようです。