下のサンプルソースは、二つのスレッド間(thread1, thread2)で共通の変数(count)を整合性を保ちながら利用(カウントアップ)する例である。
折角なので wait と signal の処理も盛り込んでみた。waitで待たされたスレッド(thread1)は、もう一つのスレッド(thread2)からのsignalにより待ち状態が解除される。
hoge.c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // usleepを使うため
/**
* 関数定義
*/
// スレッド関数1
void* threadFunc1(void* param);
// スレッド関数2
void* threadFunc2(void* param);
/**
* グローバル変数
*/
// スレッド間で変数を保護するmutex
pthread_mutex_t mutex;
// スレッド間で状態を判断するcond
pthread_cond_t cond;
// スレッド間で共有してみる変数
int count = 0;
/**
* メイン関数
*/
int main(int argc, char* argv[]) {
// スレッド1識別変数の宣言
pthread_t thread1;
// スレッド2識別変数の宣言
pthread_t thread2;
printf("initializing mutex...\n");
// mutex初期化
pthread_mutex_init(&mutex, NULL);
printf("initializing cond...\n");
// cond初期化
pthread_cond_init(&cond, NULL);
printf("creating thread1...\n");
// スレッド1の生成
pthread_create(&thread1, NULL, threadFunc1, NULL);
printf("creating thread2...\n");
// スレッド2の生成
pthread_create(&thread2, NULL, threadFunc2, NULL);
printf("joining thread1...\n");
// スレッド1の終了待ち
pthread_join(thread1, NULL);
printf("joining thread2...\n");
// スレッド2の終了待ち
pthread_join(thread2, NULL);
printf("destroying mutex...\n");
// mutex破棄
pthread_mutex_destroy(&mutex);
printf("mutex destroyed...\n");
return EXIT_SUCCESS;
}
/**
* スレッド関数1実装:
* signalが来るまでwaitするスレッド。
*/
void* threadFunc1(void* param) {
while (1) {
// mutexロック
pthread_mutex_lock(&mutex);
count++;
printf("thread1: waiting... count=%d\n", count);
// signal待ち
pthread_cond_wait(&cond, &mutex);
printf("thread1: go!\n");
// mutexアンロック
pthread_mutex_unlock(&mutex);
usleep(10000);
}
}
/**
* スレッド関数2実装:
* waitしているスレッドにシグナルを送信するスレッド。
*/
void* threadFunc2(void* param) {
while (1) {
// mutexロック
pthread_mutex_lock(&mutex);
count++;
printf("thread2: sending signal... count=%d\n", count);
/**
* wait中のスレッドに対してsignal送信。
* 複数スレッドへのsignal送信は、pthread_cond_broadcast(&cond)を使う。
*/
pthread_cond_signal(&cond);
// mutexアンロック
pthread_mutex_unlock(&mutex);
usleep(5000);
}
}
これをコンパイルするときは下のように -lpthread を指定する。
$ gcc pthread.c -lpthread
コンパイル出力された a.exe を実行すると、下のような結果が出力される。
$ a
initializing mutex...
initializing cond...
creating thread1...
creating thread2...
joining thread1...
thread1: waiting... count=1
thread2: sending signal... count=2
thread1: go!
thread2: sending signal... count=3
thread1: waiting... count=4
thread2: sending signal... count=5
thread1: go!
thread2: sending signal... count=6
thread1: waiting... count=7
thread2: sending signal... count=8
thread1: go!
thread2: sending signal... count=9
thread1: waiting... count=10
thread2: sending signal... count=11
thread1: go!
thread2: sending signal... count=12
thread1: waiting... count=13
thread2: sending signal... count=14
thread1: go!
thread2: sending signal... count=15
thread1: waiting... count=16
thread2: sending signal... count=17
thread1: go!
thread2: sending signal... count=18
thread1: waiting... count=19
thread2: sending signal... count=20
thread1: go!
thread2: sending signal... count=21
thread1: waiting... count=22
thread2: sending signal... count=23
thread1: go!
thread2: sending signal... count=24
thread1: waiting... count=25
thread2: sending signal... count=26
thread1: go!
thread2: sending signal... count=27
thread1: waiting... count=28
thread2: sending signal... count=29
thread1: go!
thread2: sending signal... count=30
thread1: waiting... count=31
thread2: sending signal... count=32
thread1: go!
thread2: sending signal... count=33
thread1: waiting... count=34
thread2: sending signal... count=35
thread1: go!
thread2: sending signal... count=36
thread1: waiting... count=37
thread2: sending signal... count=38
thread1: go!
thread2: sending signal... count=39
thread1: waiting... count=40
thread2: sending signal... count=41
thread1: go!
thread2: sending signal... count=42
thread2: sending signal... count=43
thread1: waiting... count=44
thread2: sending signal... count=45
thread1: go!
共通変数 count の操作(カウントアップ)が、ロック処理(pthread_mutex_lock)とアンロック処理(pthread_mutex_unlock)の間で実行されているので、二つのスレッド間で整合性が保たれ、正しくカウントアップされているのが分かる。
そして、thread1は、thread2からのGoサイン(pthread_cond_signal)が来るまで pthread_cond_wait で処理を待っているのも分かるはずだ。
signal送信側(thread2)は待機中スレッド(thread1)がwait中だろうが何だろうがシグナルを垂れ流す。上のログで、偶に sending signal... が2回連続して出力されているのはそのためである。
注意すべき点としては、pthread_cond_signal が一つのスレッドに対するsignal送信しか行わないということである。複数スレッドにまとめてsignal送信したい時は、pthread_cond_signal ではなく、 pthread_cond_broadcast を利用すること。
参考にさせていただいたサイト
マルチスレッドプログラミング - onishi-lab.jp
C++プログラミング入門
posted with amazlet at 12.03.25
グレゴリー サティア ダウグ ブラウン
オライリー・ジャパン
売り上げランキング: 61971
オライリー・ジャパン
売り上げランキング: 61971
PR:お買い物はAmazonで