pthreadの使い方

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


int pthread_create(pthread_t * thread, pthread_attr_t * attr, void *
(*start_routine)(void *), void * arg);
この関数でスレッドを生成します。
使用例
#include

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
#include

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
#include
#include

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);
}