2. スレッドの生成と終了(1/2)
スレッドは、pthread_createにより起動し、生成された新スレッドは引数にある関数を実行します。呼び出された関数はスレッド上で動き、その関数が終了すればスレッドも終了します。
以下からはpthread_createの引数である関数をスレッドと呼びます。スレッドの生成や終了にかかわる関数を見ていきます。
2.1 リファレンス
主にスレッドの生成にかかわる関数は下記の通りです。より詳細についてはmanコマンド、もしくはココを参照してください。
- int pthread_create( pthread_t * id, pthread_attr_t * attr, void * (*routine)(void *), void * arg);
- int pthread_join( pthread_t id, void ** thread_return );
- int pthread_detach( pthread_t id );
- void pthread_exit(void *retval );
- pthread_t pthread_self( );
pthread_create:新しいスレッドを生成します。
pthread_t * id:スレッド識別子です。主にlongで実装されている事が多いです。スレッドの起動が成功するとpthread_createが値を設定します。以降、スレッドに対してアクセスする際に必要になります。スレッド内で自分自身のスレッド識別子を参照したい場合、pthread_self 関数によって取得可能です。
pthread_attr_t * attr:スレッド属性用構造体です。スレッドを生成する時にだけ参照されます。 利用しない場合はNULLを設定する事でデフォルトの設定と同じになります(デフォルト設定:thread joinable, scheduling off, stack size default(私の環境では10M))。 pthread_attr_*関数により操作します。詳細については別章で説明します。
start_routine:スレッドが起動する関数で、引数はstart_routineの後ろにあるvoid * argです。戻り値は親プロセスがpthread_joinの第2引数がNULLではない場合、そこに設定されます。
pthread_join:スレッドの終了を待ちます。
pthread_exitを呼び出して終了するか、取り消しされて終了するのを待ちます。
thread_return:監視対象スレッドの戻り値の格納領域、NULLを設定する事で戻り値を精査しないことも可能。
pthread_detach:スレッドをデタッチ状態へ移行させます。これによって親プロセスはpthread_joinで監視しなくてもよくなり、逆に監視するとエラーになります。
pthread_exit:スレッドの終了、結果を返却します。通常は呼び出し先で使う事でスレッドを終了させます。retval にNULLではない値を入れると、その値はpthread_joinで参照できます。また、呼び出し元で使う事で、呼び出した全スレッドが終了するまで待つ事ができます。しかしプロセス自体はdefanct(つまりゾンビプロセス)扱いになります。なお、pthread_exit(retval) は、 return retval;と書く事もできます。
2.2 エラー対処
従来のC/C++にて提供されている関数でエラーが発生すると、一般的には関数は戻り値として-1を返し、エラー種別として外部変数であるerrnoに値を設定します。しかしスレッドの場合は戻り値がエラー種別になります。正常値の時は0が帰ってきます。
エラー情報を文字列で表示する strerror(3) には、errno ではなく戻り値をセットします。
2.3 サンプル
以上の関数を使ったサンプルが下記です。
/* gcc thread_sample.c -o thread_sample -W -Wall -lpthread */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include <ctype.h> void * thread_function( void * arg ); int main( int argc, char ** argv ) { ( void )argc; pthread_t pt; char * rtn_p = 0; char buf[256]; strcpy( buf, argv[0] ); fprintf( stdout, "buf :[%s]\n", buf ); pthread_create( &pt, NULL, &thread_function, ( void * )buf ); pthread_join( pt, ( void ** )&rtn_p ); /* pthread_detach( pt ); */ fprintf( stdout, "rtn_p:[%s]\n", rtn_p ); return 0; } void * thread_function( void * arg ) { char * buf = malloc( strlen(( char * )arg ) + 1 ); strcpy( buf, ( char * )arg ); size_t i; for( i = 0; i < strlen( buf ); i ++ ) { buf[i] = toupper( buf[i] ); } pthread_exit( buf ); }
