C言語のスレッド同期を使って1〜10の数字を順番に出力する方法
複数のスレッドが与えられたとき、それぞれの役割(優先度)に従って1から10までの数字を正しい順序で出力するプログラムを、C言語で作成します。
スレッドとは?
スレッドとは、プログラムの内部で動作する軽量プロセスのことです。ひとつのシンプルなプログラムの中に、n個のスレッドを含めることができます。
Javaと異なり、C/C++の言語仕様自体はマルチスレッドをサポートしていません。C/C++でマルチスレッドを実現する際の標準として広く使われているのが、POSIX Threads(Pthreads)です。C言語にはマルチスレッドアプリケーション向けの組み込みサポートが用意されておらず、この機能は完全にオペレーティングシステム(OS)に依存します。
プログラムでの実装方法
スレッド関連の関数を使用するには、ヘッダーファイル #include <pthread.h> をインクルードします。このヘッダーには、pthread_create() など、スレッド操作に関わるすべての関数が宣言されています。
今回の課題は、gccコンパイラに付属するpthread標準ライブラリを使って、複数のスレッドを同期させることです。基本的な考え方は次のとおりです。
- 1つ目のスレッド(even)は偶数を出力する
- 2つ目のスレッド(odd)は奇数を出力する
- ミューテックスと条件変数を使い、交互に制御を渡しながら1から10まで順番に表示する
その結果、出力にはスレッドの実行順序に基づいて1から10までの数字が正しく並びます。
アルゴリズム
Start
Step 1 -> グローバル変数として int MAX=10 と count=1 を宣言する
Step 2 -> pthread_mutex_t 型の変数 thr と pthread_cond_t 型の変数 cond を宣言する
Step 3 -> 関数 void *even(void *arg) を宣言する
While(count < MAX) ループ
pthread_mutex_lock(&thr) を呼び出す
While(count % 2 != 0) ループ
pthread_cond_wait(&cond, &thr) を呼び出す
End
count++ の値を出力する
pthread_mutex_unlock(&thr) を呼び出す
pthread_cond_signal(&cond) を呼び出す
End
pthread_exit(0) を呼び出す
Step 4 -> 関数 void *odd(void *arg) を宣言する
While(count < MAX) ループ
pthread_mutex_lock(&thr) を呼び出す
While(count % 2 != 1) ループ
pthread_cond_wait(&cond, &thr) を呼び出す
End
count++ の値を出力する
pthread_mutex_unlock(&thr) を呼び出す
pthread_cond_signal(&cond) を呼び出す
End
pthread_exit(0) を呼び出す
Step 5 -> main() 内で
pthread_t thread1 と pthread_t thread2 を作成する
pthread_mutex_init(&thr, 0) を呼び出す
pthread_cond_init(&cond, 0) を呼び出す
pthread_create(&thread1, 0, &even, NULL) を呼び出す
pthread_create(&thread2, 0, &odd, NULL) を呼び出す
pthread_join(thread1, 0) を呼び出す
pthread_join(thread2, 0) を呼び出す
pthread_mutex_destroy(&thr) を呼び出す
pthread_cond_destroy(&cond) を呼び出す
Stop
サンプルコード
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
int MAX = 10;
int count = 1;
pthread_mutex_t thr;
pthread_cond_t cond;
void *even(void *arg){
while(count < MAX) {
pthread_mutex_lock(&thr);
while(count % 2 != 0) {
pthread_cond_wait(&cond, &thr);
}
printf("%d ", count++);
pthread_mutex_unlock(&thr);
pthread_cond_signal(&cond);
}
pthread_exit(0);
}
void *odd(void *arg){
while(count < MAX) {
pthread_mutex_lock(&thr);
while(count % 2 != 1) {
pthread_cond_wait(&cond, &thr);
}
printf("%d ", count++);
pthread_mutex_unlock(&thr);
pthread_cond_signal(&cond);
}
pthread_exit(0);
}
int main(){
pthread_t thread1;
pthread_t thread2;
pthread_mutex_init(&thr, 0);
pthread_cond_init(&cond, 0);
pthread_create(&thread1, 0, &even, NULL);
pthread_create(&thread2, 0, &odd, NULL);
pthread_join(thread1, 0);
pthread_join(thread2, 0);
pthread_mutex_destroy(&thr);
pthread_cond_destroy(&cond);
return 0;
}
実行結果
上記のプログラムをコンパイルして実行すると、次のような出力が得られます。
1 2 3 4 5 6 7 8 9 10
ポイントの解説
pthread_mutex_lock / unlock: 共有変数 count への同時アクセスを防ぎ、データ競合を回避します。
pthread_cond_wait: 自分の番(偶数/奇数)が来るまでスレッドを待機状態にします。
pthread_cond_signal: 待機中のもう一方のスレッドに「自分の番が来た」ことを通知し、処理を交代させます。
このように、ミューテックスによる排他制御と条件変数による待機・通知を組み合わせることで、複数のスレッドが協調して動作し、数字が必ず昇順に出力されることが保証されます。
-
C言語でO(1)の追加メモリ領域のみを使ってn×nのスパイラル行列を出力する方法
正の整数 n が与えられたとき、追加の作業用メモリを O(1) しか使用せずに、時計回り方向の n×n スパイラル行列を生成して出力する方法を解説します。スパイラル行列とは、円の原点から出発し、時計回りに渦を描くように値を埋めていく行列のことです。ここでは、2 → 4 → 6 → 8 → 10 → 12 → 14 → 16 → 18 というように偶数を渦状に配置した行列を、O(1) の空間計算量で出力することを目標とします。以下にスパイラル行列の例を示します。実行例入力: 3 出力: 9 8 7 2 1 6 3 4 1メモリを無制限に使えばこの問題は簡単に解けますが、そ
-
Cプログラムで行列を対角パターンに沿って数値出力する方法
この課題は、n×nの行列を対角パターンで出力することです。 例えば n が 3 の場合、対角パターンに従って行列を出力すると、次のような配置になります。 そして、実際の出力結果は以下の通りです。 実行例 Input: 3 Output: 1 2 4 3 5 7 6 8 9 Input: 4 Output: 1 2 4 7 3 5 8 11 6 9 12 14 10 13 15 16 考え方 一見すると、「数値 n を受け取り n×n の行列を生成し、それを対角方向に走査しながら別の行列へ値を格納する」というアプローチが思い浮かびます