2012年04月03日

[C++]POSIXスレッド標準(pthread)を使ったマルチスレッドプログラミング

今回はPOSIXスレッド標準(pthread.h)を利用したC++マルチスレッドプログラミング手法を紹介する。

下のサンプルソースは、二つのスレッド間(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++プログラミング入門
グレゴリー サティア ダウグ ブラウン
オライリー・ジャパン
売り上げランキング: 61971

PR:お買い物はAmazonで
posted by 寄り道退屈男 at 11:33 | Comment(0) | TrackBack(0) | C++
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス: [必須入力]

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
※ブログオーナーが承認したコメントのみ表示されます。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/54786696
※ブログオーナーが承認したトラックバックのみ表示されます。
※言及リンクのないトラックバックは受信されません。

この記事へのトラックバック