前提・実現したいこと
C言語において並列処理(pthread.h)を用いて0からnまでの総和を求めるプログラムの計算を行いたいと考えています。
該当のソースコード
ワークフローとしては
1. DATA_NUMで0から幾つまでの数の総和を求めるのか決め、DATANUMの値を基にそのサイズのdata二次元配列を作成する。 2. data[i][0]にiを代入、data[i][1]にdata[i][0]が計算済みか否かのフラグを導入 3. 並列処理部分の関数(do_calc)で並列処理を行い、data[i][0]の値をグローバル変数のsumに値を追加 , [i][1]に処理を行ったスレッドの番号を追加 4. main関数でsumをprintfし、各スレッドがsumに何回加算したか計算する。
C
1#include <pthread.h> 2#include <stdio.h> 3#include <stdlib.h> 4#include <unistd.h> 5 6 7// 幾つのスレッドで並列処理を行うか 8#define THREAD_NUM 4 9 10// いくつまでの数の総和を求めるか 11#define DATA_NUM 100000 12 13// 結果を収納する配列 14unsigned long data[DATA_NUM][2]; 15 16// 総和を収納する配列 17unsigned long sum = 0; 18 19//Mutexオブジェクト 20pthread_mutex_t mutex; 21 22 23pthread_t tid[THREAD_NUM]; // スレッドID を保持する配列 24int param[THREAD_NUM]; 25 26 27// プロトタイプ処理 28void *do_calc(void *); 29 30 31void *do_calc(void* arg) { 32 33 // 1回の処理で担当する回数 34 int Number_Interval; 35 Number_Interval = DATA_NUM/THREAD_NUM; 36 37 //StartするIndex 38 int Start_Index , *id; 39 id = arg; 40 Start_Index = *id * Number_Interval; 41 42 //終わるIndex 43 int Finish_Index; 44 Finish_Index = Start_Index + Number_Interval; 45 46 for(int i = Start_Index;i<Finish_Index;i++){ 47 48 // もし値が0(未作業)の場合は、data[i][0]の値をグローバル変数のsumに追加した後にdata[i][1]にスレッド番号を収納 49 if (data[i][1] == 0){ 50 pthread_mutex_lock(&mutex); 51 sum = sum + data[i][0]; 52 data[i][1] = arg; 53 pthread_mutex_unlock(&mutex); 54 } 55 56 } 57 pthread_exit(NULL); 58 59 60} 61 62 63int main(){ 64 65 // DATA_NUM-1の範囲で、data[i][0]にはiを代入 、 data[i][1]には0を代入 66 for(int i = 0; i <DATA_NUM;i++){ 67 data[i][0] = i; 68 data[i][1] = 0; 69 } 70 71 //Mutexオブジェクトの初期化 72 pthread_mutex_init(&mutex, NULL); 73 74 75 //指定された数のスレッドを作成する。 76 for (int i =0; i < THREAD_NUM; i++){ 77 param[i] = i; 78 pthread_create(&tid[i],NULL,do_calc,¶m[i]); 79 } 80 81 82 for(int i=0; i<THREAD_NUM; i++){ 83 pthread_join(tid[i], NULL); 84 } 85 86 for(int i=0; i < DATA_NUM; i++){ 87 printf("%lu \n",data[i][1]); 88 89 90 } 91 92 printf("Sum is %lu \n",sum); 93 94 95 96} 97 98 99 100//i=0からdata[i][1]を調べて、それが0だったら、「作業」が済んでいないとみなして、data[i][0]の値をグローバル変数sumに加算する。 101 102//「作業済み」として、data[i][1]にスレッドを区別する番号(例えば、1からTHREAD_NUMのどれか)を代入して次のiを調べる。 103 104//iが DATA_NUM-1まで調べたら各スレッドは終了する。 105 106//すべてのスレッドが終了したら、mainの中で、sumの値と、各スレッドがsumに何回加算したかを表示する。 107 108//各スレッドがsumに何回加算したかは、data[i][1]を全部調べて、その値を表示してください。 109 110//sumを正しく計算するために、グローバル変数sumへの加算時と、data[i][1]で作業済みかどうかのチェックなどで必要な排他制御を行うプログラムにしてください。 111//DATA_NUMが100の場合、0から99の和ですから、4950が答えになるはずです。
発生している問題・エラーメッセージ
大方の実装は終わっているのですが、DATA_NUMの値が100000を超えた時の総和がおかしくなる、ワークフロー4.の「各スレッドがsumに何回加算したか計算する」の実装を行うにあたってスレッド番号が大きくなってしまう(実際の0,1,2,3...)というエラーが解決できていないです。
DATA_NUM = 100 THREAD_NUM = 4 の時 4212384 ... 4212388 .... 4212392 ... 4212396 ------------- Sum is 4950 -------------
DATA_NUM = 1000 THREAD_NUM = 4 の時 ------------- Sum is 4995000 ------------- DATA_NUM = 10000 THREAD_NUM = 4 の時 ------------- Sum is 4995000 ------------- DATA_NUM = 100000 THREAD_NUM = 4 の時 ------------- Sum is 5 -------------
補足情報(FW/ツールのバージョンなど)
paiza ioでコンパイルしました。
>DATA_NUMの値が100000を超えた時の総和がおかしくなる
とありますが、別にDATA_NUMの値が100000以外も全部間違った総和ですよ?
まずTHREAD_NUMを1、DATA_NUMを10辺りにしてデバッグしたほうが良いかと思います。
仕様の説明が曖昧でした。総和の意味は0~(DATA_NUM-1)という意味で言っていました。その場合は100000以外の総和は正しいと思います。
https://ja.wolframalpha.com/input/?i=0%2B1%2B2%2B...%2B99
回答4件
あなたの回答
tips
プレビュー