Hatena::ブログ(Diary)

jiroの日記 このページをアンテナに追加 RSSフィード

2003-11-11

[]pthreadの使い方

pthreadについて詳しく書いてあるページがあまり見つからなかったので
簡単にpthreadの使い方をメモします。

int  pthread_create(pthread_t  *  thread, pthread_attr_t * attr, void *
                                                       (*start_routine)(void *), void * arg);
この関数でスレッドを生成します。
使用例
#include <pthread.h> void * evaluate_responce(void *); typedef struct { char *c; int i; long l; } pth_arg; /* thread_func関数に値を渡すときの構造体 */ /* スレッド関数 */ void * thread_func(void *arg){ pth_arg *this_arg; this_arg = arg; printf("c=%s\ni=%d\nl=%d\n", this_arg->c, this_arg->i,this_arg->l); } int main(){ pthread_t th[2]; /* スレッド関数に複数の値を渡したい場合構造体を用いる */ pth_arg pth; pth.c = "thread_funcの中から呼ばれてます"; pth.i = 99; pth.l = 1234567890; /* スレッドの生成 */ pthread_create(&th[0], NULL, thread_func, (void *)&pth); /* スレッドの生成 */ pthread_create(&th[1], NULL, thread_func, (void *)&pth); /* メイン関数が先に終了しないための処置 */ sleep(1); }
sleepなんかつかってなんかスマートじゃありませんが、これが基本のスレッドの生成です。 次にsleepを使ってるところをもう少しスマートにするためにpthread_joinを用います。 int pthread_join(pthread_t th, void **thread_return) 実際の使い方は
#include <pthread.h> #include <stdlib.h> void * evaluate_responce(void *); typedef struct { int i; long l; } pth_arg; /* thread_func関数に値を渡すときの構造体 */ /* スレッド関数 */ void * thread_func(void *arg){ pth_arg *this_arg; printf("i=%d\nl=%d\n", ((pth_arg *)arg)->i,((pth_arg *)arg)->l); ((pth_arg *)arg)->i = 10; return arg; } int main(){ pthread_t th[2]; /* スレッド関数に複数の値を渡したい場合構造体を用いる */ pth_arg pth[2]; int error; pth[0].i = 99; pth[0].l = 1234567890; pth[1].i = 1; pth[1].l = 987654321; /* スレッドの生成 */ pthread_create(&th[0], NULL, thread_func, (void *)&pth[0]); pthread_create(&th[1], NULL, thread_func, (void *)&pth[1]); /* メイン関数が先に終了しないための処置 */ error = pthread_join(th[0], (void **)&pth[0]); printf("error=%d\ni=%d\nl=%d\n", error,pth[0].i,pth[0].l); error = pthread_join(th[1], (void **)&pth[1]); printf("error=%d\ni=%d\nl=%d\n", error,pth[1].i,pth[1].l); }
となるはずだが、うちの環境ではうまく動かない。構造体の始めの変数が おかしくなってしまう。原因がわからない。。。。。 ということで、とりあえずpthread_joinの2番目の引数をNULLにすることでとりあえず 戻り値を使わない方向でw そして、つぎにmutexの説明。 mutexはスレッド間で同時にひとつのスレッドしか操作許可を与えないためのもの。 int pthread_mutex_lock(pthread_mutex_t *mutex)); で、それ以降の操作をロックします。ロックされている間他のpthread_mutex_lock 関数はブロックされます。 int pthread_mutex_unlock(pthread_mutex_t *mutex)); でロックが解除されます。ロックが解除されると他のpthread_mutex_lock を実行しようとしてブロックされたいたスレッドが実行可能になります。 ようするにスレッド同士で競合するとまずい個所は pthread_mutex_lock(......)とpthread_mutex_unlock(....)で囲むことで スレッドセーフになります。その引数となる*mutexは初期化されてないといけないので 初期化しておきましょう。通常は pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; とします。 最後にひとつpthread_cond_wait, pthread_cond_signalを紹介します。 pthread_cond_wait,pthread_cond_signalは待機条件と条件の合図を行う関数です。 これはおそらくサンプルソースを見せたほうが早いと思うので下に示します。
#include <stdio.h> #include <stdlib.h> #include <pthread.h> void * evaluate_responce(void *); static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond; typedef struct { struct sockaddr_in *srv; int sock; int be; } pth_arg; /* Jiro Add evaluate_responce関数に値を渡すときの構造体 */ void * evaluate_responce(void *arg){ printf("1\n"); printf("2\n"); printf("3\n"); printf("4\n"); printf("5\n"); sleep(1); printf("6\n"); printf("7\n"); /* mutex ロック */ pthread_mutex_lock(&mt); printf("8\n"); printf("9\n"); /* 条件を真にする * このシグナルを送ることで待機しているmain関数のpthread_cond_wait * が動き出す。したがってprintf("9\n");を実行するスレッドはひとつのみ */ pthread_cond_signal(&cond); /* mutex アンロック */ pthread_mutex_unlock(&mt); } int main(){ pthread_t *th; pth_arg pth; th = (pthread_t *) malloc(sizeof(pthread_t)*5); /* pthread_condの初期化 */ pthread_cond_init(&cond, NULL); pth.sock=1; pth.be=3; /* スレッドは5個走らせる */ pthread_create(&th[0], NULL, evaluate_responce, (void *)&pth); pthread_create(&th[1], NULL, evaluate_responce, (void *)&pth); pthread_create(&th[2], NULL, evaluate_responce, (void *)&pth); pthread_create(&th[3], NULL, evaluate_responce, (void *)&pth); pthread_create(&th[4], NULL, evaluate_responce, (void *)&pth); /* mutexロック */ pthread_mutex_lock(&mt); /* 条件が真になるまで待機 */ pthread_cond_wait(&cond, &mt); printf("Hello Pthread!!\n"); pthread_mutex_unlock(&mt); }

2003-10-30

[]fork()の動作

fork()

fork()

プロセスを新たに生成するには fork() システムコールによる。実は、 $ ps -e で表示されるすべてのプロセスは init から fork によって生成されたものである。

int fork() /* 新しいプロセスを生成 */

/* 成功するとプロセスIDと0を、失敗するとー1を返す */

fork は元のプロセスのクローンを作り出し、新しいプロセスIDを与える。これが、「子プロセス」(child process)である。元のプロセスは消滅するわけではなくて、そのまま、生き続ける。これを、子プロセスに対して「親プロセス」と呼ぶ。

fork()は正常にリターンすると、2つの「返り値」をもつ。1つは0であり、もう1つは「プロセスID」である。ただし、この「返り値」のそれぞれを受け取る親プロセスが受け取る「返り値」が子プロセスのプロセスIDであるということは、「子を生成した親プロセスは子プロセスのことを認識している」(子を作りっぱなしではない)ということである。一方、子プロセスの方も自分がどの親から生まれたかを認識している( getppid() )。

それでは、このことをテストしてみよう。

forktest1.c

#include <stdio.h>

main()

{

int i;

printf("\t(%s)プロセスID..........%d\n","元",getpid());

printf("\t(%s)親プロセスID........%d\n","元",getppid());

if( (i=fork()) == 0 )

/* execute only in CHILD process */

{

printf("\t子プロセスでのfork()の値 : %d\n",i);

printf("\t(%s)プロセスID...........%d\n","子",getpid());

printf("\t(%s)親プロセスID.........%d\n","子",getppid());

}

else

/* execute only in PARENT process */

{

printf("\t親プロセスでのfork()の値 : %d\n",i);

printf("\t(%s)プロセスID...........%d\n","親",getpid());

printf("\t(%s)親プロセスID.........%d\n","親",getppid());

}

}


ipc$ cc forktest1.c

ipc$ a.out

(元)プロセスID..........978

(元)親プロセスID........942

子プロセスでのfork()の値 : 0

(子)プロセスID...........979

(子)親プロセスID.........978

親プロセスでのfork()の値 : 979

(親)プロセスID...........978

(親)親プロセスID.........942

ipc$