ファイヤープロジェクト
スレッドのデタッチとjoin
2007-02-05T22:50+09:00   matsu
スレッドのデタッチと合流について調べてみた.
スレッドは終了してもリソース(スレッドディスクリプタとスタック)が保持される. このリソースは,他のスレッドが開放するまで保持され続ける. この開放処理が
#include <pthread.h>
int pthread_join(pthread_t th,
                 void **thread_return);
である. 返り値は0なら成功,それ以外の場合にはエラーコードが格納されている. 引数は以下.
th
スレッド識別子. join対象のスレッドをpthread_createした際に取得したもの.
thread_return
join対象のスレッドのイニシャル関数の返り値(void *)の格納領域のポインタ.
この関数を呼び出した時点で,対象のスレッドが終了していないければ,そのスレッドが終了するのを待ってからリソースは開放される. プロセスでforkした後のwaitをイメージすれば近いだろうか. だから,この関数はその名の通り,スレッドの合流と解した方が,その挙動を解しやすいかもしれない.
スレッドが終了したら,別のスレッドでその終了したスレッドのリソースを開放しなければならない. だが,プログラムによっては,このリソース開放処理を記述する適切な箇所が見当たらなかったり,プログラム構造に制約を課してしまう場合がある. このような場合には,該当スレッドにてpthread_createする際の属性にてデタッチ属性を指定するか(※),
#include <pthread.h>
int pthread_detach(pthread_t th);
を呼び出す. 返り値は0なら成功,0以外ならエラーコードが設定されている. 引数にはやはり,デタッチ対象のスレッドの識別子を指定する. スレッドをデタッチすることによって,対象のスレッドは終了時にリソースが開放されることを保証される. ただし,合流可能状態でなくなり,pthread_joinできなくなる. デタッチされたスレッドに対しpthread_joinを実行すると,エラーが返される. また,pthread_joinにて合流待ちされているスレッドに対してpthread_detachを呼び出すと,何も処理されず0が返される.
※ 別頁にて記述.
pthread_join,pthread_detachを実行するサンプルを以下に示す.
このサンプルでは,main関数にて二つのスレッドa,bを生成し,どちらも関数myThreadを実行する. myThreadでは,スレッドaは2秒sleepし,その間にmainスレッドはスレッドaに対するpthread_joinにまで到達する.
  // スレッドaが終了するのを待つ.
  status = pthread_join(thread_a, &thread_return);
  if (status != 0) {
    fprintf(stderr, "\n");
    fprintf(stderr,"failed to join thread_a");
    fprintf(stderr, "\n");
    exit(1);
  } else {
    // スレッドのイニシャル関数の返り値をチェック.
    assert(&thread_a_arg == thread_return);
  }
その後スレッドaはpthread_detachしようとするが,すでにmainスレッドにて合流待ちされているので,デタッチされずにpthread_detach呼び出しは完了してしまう(下図破線内).
  // スレッドaのみ2秒sleep
  if (my_thread_arg->printVal == 'a') {
    sleep(2);
  }

  // 自スレッド識別情報の取得
  pthread_t self_thread = pthread_self();

  // デタッチ
  int status = pthread_detach(self_thread);
  if (status != 0) {
    fprintf(stderr, "failed to detatch\n");
  }
なお,スレッドa内では,自分自信のスレッド識別子を取得するために,
#include 
pthread_t pthread_self(void);
を呼び出している. さて,スレッドbはpthread_createされた後即座に(メインスレッドにてpthread_joinされる前に)pthread_detachをしてしまうので,このpthread_detach呼び出しによって,合流可能状態ではなくなる. メインスレッドは後からスレッドbに対しpthread_joinするが,スレッドbは合流可能状態ではないので失敗する.
  // スレッドbはデタッチしているので,joinに失敗する.
  status = pthread_join(thread_b, &thread_return);
  if (status != 0) {
    fprintf(stderr, "\nexpected result\n");
  } else {
    fprintf(stderr, "\n");
    fprintf(stderr,"successed to join thread_a");
    fprintf(stderr, "\n");
    exit(1);
  }
以上のシーケンスを以下に示す.
実行結果は以下.
$ ./join_thread 
bababaaba
expected result
よくわからないが,とにかく"expected result"というふうに,スレッドbのjoinに失敗したことがわかる.
matsu(C)
Since 2002
Mail to matsu