pthread_cond_waitとpthread_cond_signalによるスレッド間の通知
(プログラムの概要)
キーボードやパケットの入力を受け付けるスレッドがあり、入力されたデータを受け取って必要な処理を行うスレッドがあったとします。処理を行うスレッドはデータが入力されたかを定期的に(10msに一回のように)チェックしていたのでは無駄が多そうです。そこで、普段は実行を停止していて、「データが到着したから処理してね」という通知を受けると処理を再開できるようにします。
|
/*
* sample program
* synchronous of threads test program
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#define BUFSIZE 256
char buf[BUFSIZE];
pthread_mutex_t mutex;
pthread_cond_t cond;
void *output(void*);
int main(void)
{
int loop = 1;
char input[BUFSIZE];
pthread_t thread_id = 0;
printf("sample program(%s) start\n", __FILE__);
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
/* create new thread */
if(pthread_create(&thread_id, NULL, output, NULL) < 0){
perror("pthread_create error");
exit(1);
}
while(loop){
memset(input, 0, BUFSIZE);
read(STDIN_FILENO, input, BUFSIZE -1);
pthread_mutex_lock(&mutex);
memcpy(buf, input, BUFSIZE);
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
if(strncmp(input, "quit\n", 5) == 0){
loop = 0;
}
}
if(pthread_join(thread_id, NULL) < 0){
perror("pthread_join error");
exit(1);
}
printf("sample program end\n");
return 0;
}
void *output(void *arg)
{
int loop = 1;
char outbuf[BUFSIZE];
printf("thread start\n");
while(loop){
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
memcpy(outbuf, buf, BUFSIZE);
printf("%s\n", outbuf);
if(strncmp(outbuf, "quit\n", 5) == 0){
loop = 0;
}
pthread_mutex_unlock(&mutex);
}
printf("thread end\n");
pthread_exit(0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
(プログラムの概要)
キーボードからの入力を待ち、入力された文字列を別スレッドに渡して表示を行うプログラムを作ります。「quit」と入力されたら終了します。
mainスレッド28L~31L:スレッドの生成
表示を行うoutputスレッドを作ります。
33L~43L:入力を受け付ける
標準入力から入力を受付、取得したデータを外部メモリにコピーしpthread_cond_signal()でデータの到着をoutputスレッドに通知しています。
45L~48L:スレッドの終了を待つ。
outputスレッドの終了を待ってリソースを回収しています。
outputスレッド
pthread_cond_wait()を使ってデータ到着までスリープします。mainからのpthrad_cond_signal()によって起こされ標準出力に文字列を表示します。
pthread_cond_wait()は第二引数(mutex)のunlockを行ってスリープに入ります。また、起動される時はmutexをロックした状態で起動されます。よってpthread_cond_wait()をコールする前にmutexがロックされている必要があります。
(コンパイルと動作)
gcc -Wall -o cond cond.c -lpthread
キーボードから文字を入力すると入力された文字が表示されます。表示しているのはoutputスレッドなのでデータがきちんと受け渡されていることがわかります。
(補足)
pthread_cond_signal()とpthread_cond_wait()によるスレッド間のデータ送受信では、データを直接渡すことはできないので、決まったバッファやキューなどを使用します。複数スレッドで扱うことになるのでmutexによる排他制御が必要になります。直接データを送信し、好きなときに処理できるようにする(非同期)方法はsigqueue()とsigwaitinfo()のページで説明します。 次回は複数スレッドの同期です。