• 締切済み

C言語のプログラムにて二つの処理を並列させる方法はあるのでしょうか?

C言語の並列処理について調べているのですが、並列処理はfor文などの単調な処理を並列処理にすることで実行を早くするということがわかったのですが、実行ファイル内で同時に二つの違う動作をさせることは可能なのでしょうか?

みんなの回答

回答No.6

#5 です。サンプルプログラムが長くなってしまった関係で、コメントは別にさせていただきました。  まず、最初に↓の pdf ファイルをご覧になってください。 www.xfile09.com/fig/algo1.pdf >並列処理はfor文などの単調な処理を並列処理にすることで実行を早くするということがわかったのですが、 これは data parallelism と呼ばれているテーマです。 >実行ファイル内で同時に二つの違う動作をさせることは可能なのでしょうか? 一方、これは task parallelism と呼ばれているテーマです。 http://techon.nikkeibp.co.jp/article/TOPCOL/20080922/158319/  巷では、同時に二つ以上の違う動作を行うには、セマフォやミューテックスなどが必須であって、その実現は困難であるとされ、アメリカが躍起になっている分野です。 http://www.nytimes.com/2008/04/30/technology/30lab.html?_r=1 この問題は現在、難解な問題と捉えられていますが、考えを自由にプログラミングができる線形思考から、もはや自由にプログラミングはできない非線形思考へと考えを変えることで、簡単に対応可能です。また、新たなプログラミング言語を覚える必要もありません(C言語のままでOK)。  その証明として、特に Mac OSX を講義に使われている京都産業大学や琉球大学、また九州大学や東京大学の学生の方が実際に現実を体験していただきたく、ここにC言語による同時ソーティングによるサンプルプログラムを 回答番号No. 5 示します。UNIX系である Linuxユーザーの方も体験できるでしょう。  ワーキングディレクトリ内に以下の3つのプログラムを置き、sort_main.c 、sort_sub.c の2つをコンパイルしてください。実行は、シェルのコマンドラインから、   ./a.out と入力し、起動してください。  sort_mainプログラムが ./a.out によって起動されることから親プロセスとなり、この親プロセスが sort_sub プログラムを「&」の並列処理のために起動されます。すなわち、sort_sub は子プロセスという立場にあります。  親プロセスは、子プロセスのバブルソートよりは処理が速いシェルソートを使うことにし、速度の違いによってどのような同時実行の違い(ハード的違い)があるのかを見てわかるようにしてみました。  親子の関係は、共有メモリの掲示板(sorting.h)と親から子へ、子から親への声を掛け合う(シグナル)ことで実現しています。それ以外の道具は必要ありません。  子プロセスは、起動後、親プロセスに対して「 用意できたよ」と掲示板に書いて声を掛け( signal送信)、親プロセスの返事を待ちます( pause() )。その子プロセスに対して親プロセスは、「わかったよ」と返事をしてあげる( kill() signal送信)ことで2つのプログラムは同時に動き始めるのです。  Macの場合は、アクティビティモニタを先に開いてから、./a.out を入力してください。プロセスの稼働状況がどのようになっているのか、目で確認してください。わからなければ、何度も ./a.out を実行し、アクティビティモニタを見れば良いでしょう。この並列処理の実現に際し、線形プログラミングに使われるセマフォやミューテックスは一切使っていないシンプルなプログラミング構造であることを確認してください。また、並列処理はC言語によって実現されていることを確認してください。

参考URL:
www.xfile09.com/programming.html
回答No.5

/* 共通事項リストアップ・定義等ヘッダーファイル * file name: sorting.h * * プロセス間での共通項を列挙し、不用意な間違いを少なくする。 * Cの線形構造を利用する。 */ #define PROCS 2 /* 全プロセス数(Dual; core) */ #define CHILD 1 /* 子プロセス1 */ #define PARENT 0 /* 親プロセス */ #define ON 1 #define OFF 0 #define N 100000 /* 10万個 */ struct set1 { /* common variable */ int dat[N], temp[N]; /* data buffer */ signed char flag[PROCS]; /* condition flag */ pid_t id_number[PROCS]; /* id code */ } *ptr; /******* ここまで **********/ /* A sample program of task parallelism by Gcc on Mac OSX * file name: sort_main.c * compile: gcc sort_main.c * execution: ./a.out */ #include <stdio.h> /* for printf() */ #include <unistd.h> /* for getpid() */ #include <stdlib.h> /* for exit() */ #include <string.h> #include <time.h> #include <sys/types.h> /* for shared memory */ #include <sys/ipc.h> /* 〃 */ #include <sys/shm.h> /* 〃 */ #include <sys/stat.h> #include <signal.h> /* for signal */ #include <errno.h> #include "sorting.h" /* 共通 struct構造体 */ #define CODE 999 /* 適当に変更のこと */ void shell_sort(int *, int); void pri_out(char *, int *, char *); double second(void); void handler(int); int main(void) { int shmid; /* 共有メモリ関連 */ void *shmaddr; /* 〃 */ char command_line[64]; int i; double start; /* 共有メモリの確保 */ if (((shmid = shmget(CODE, sizeof(*ptr) + 2, IPC_CREAT | S_IRUSR | S_IWUSR)) == -1) || ((shmaddr = shmat(shmid, NULL, 0)) == (char *)-1)) { perror("Shared memory set"); exit(1); } /* 共有メモリに struct構造体をあてがう */ ptr = (struct set1 *)shmaddr; /* 自身プロセスIdを記録する */ ptr->id_number[PARENT] = getpid(); /* シグナルハンドラー登録 */ signal(SIGCONT, handler); /* 共有メモリに乱数を用意 */ srand(time(NULL)); for(i=0;i<N;i++) ptr->temp[i] = ptr->dat[i] = (int)rand() % N + 1; /* 乱数データの出力 */ pri_out("Random data:", ptr->temp, "\n\n"); /* バックグランドで同時計算可に*/ ptr->flag[PARENT] = ON; // 子プロセス完了まで待つ sprintf(command_line, "./sort_sub %d &", shmid); if (system(command_line) != 0) { perror("Shell command line error"); exit(1); } /* 子プロセスの順延に配慮 */ fprintf(stderr, "Program setting now"); while (ptr->flag[PARENT] != OFF) { fprintf(stderr, "."); sleep(1); } /* 子プロセスへ並列計算するようシグナルを送信 */ ptr->flag[PARENT] = ON; // 計算状態に有り ptr->flag[CHILD] = OFF; // 並列計算せよ kill(ptr->id_number[CHILD], SIGCONT); /* 乱数データをソーティング */ start=second(); shell_sort(ptr->temp, N); /* 結果の出力 */ fprintf(stderr, "\n"); printf("The executed time of %d data by Shell sort is %.5f sec.\n", N, second() - start); pri_out("\n\nSorted data:", ptr->temp, ""); /* 計算終了まで待機(dead_lockの回避) * 作業継続入力後も子プロセスが処理中なら1秒休む。 * ただし、処理が完了したならシグナル等で起こされる。 */ while (ptr->flag[PARENT] != OFF) { // 子プロセスが操作 fprintf(stderr, "."), fflush(stderr); sleep(1); } fprintf(stderr, "\n"); /* 子プロセスのプログラム終了送信 */ ptr->flag[CHILD] = ON; // 計算終了せよ kill(ptr->id_number[CHILD], SIGCONT); /* 共有メモリの解除 */ if (shmdt(shmaddr) == -1 || shmctl(shmid, IPC_RMID, 0) == -1) { perror("Shared memory closed"); exit(1); } return 0; } /* シェルソート */ void shell_sort(int d[], int n) { int i, j; int temp; for (i = 1; i < n; i++) { temp = d[i]; for (j = i - 1; j >= 0 && d[j] > temp; j--) d[j + 1] = d[j]; d[j + 1] = temp; } } void pri_out(char *comment, int a[], char *tail) { int i; fprintf(stderr, "%s\n", comment); for (i = 0; i < 100; i++) fprintf(stderr, "%d ", a[i]); fprintf(stderr, " .... "); for (i = N-100; i < N; i++) fprintf(stderr, "%d ", a[i]); fprintf(stderr, "%s\n", tail); } /* 稼働時間測定 */ double second() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + tv.tv_usec / 1.0e6; } /* 何もしないシグナル処理関数 */ void handler(int dummy) { ; } /******* ここまで **********/ /* A sample program of task parallelism by Gcc on Mac OSX * file name: sort_sub.c * compile: gcc sort_sub.c -o sort_sub * execution: Don't execute from command line!! */ #include <stdio.h> /* for printf() */ #include <unistd.h> /* for getpid() */ #include <stdlib.h> /* for exit() */ #include <sys/types.h> /* for shared memory */ #include <sys/ipc.h> /* 〃 */ #include <sys/shm.h> /* 〃 */ #include <sys/stat.h> #include <signal.h> /* for signal */ #include <errno.h> #include "sorting.h" /* 共通 struct構造体 */ void bubble_sort(int *, int); double second(void); void handler(int); int main(int argc, char *argv[]) { int shmid; /* 共有メモリ関連 */ void *shmaddr; /* 〃 */ double start; /* 親プロセスから受け継ぐ */ shmid = atoi(argv[--argc]); if ((shmaddr = shmat(shmid, NULL, 0)) == (char *)-1) { perror("Shared menory set"); exit(1); } /* 共有メモリに struct構造体をあてがう */ ptr = (struct set1 *)shmaddr; /* 自身プロセスIdを記録する */ ptr->id_number[CHILD] = getpid(); //ptr->flag[CHILD] = OFF; /* シグナルハンドラー登録 */ signal(SIGCONT, handler); /* 親プロセスに「スタンバイ ok!」を知らせる */ ptr->flag[PARENT] = OFF; // スタンバイ ok kill(ptr->id_number[PARENT], SIGCONT); while (1) { /* 親プロセスからのシグナルを待つ */ pause(); if (ptr->flag[CHILD] != OFF) // 計算終了 break; else { // 計算開始 fprintf(stderr, " And sub program runninng now. "); fflush(stderr); start = second(); bubble_sort(ptr->dat, N); // バブルソート fprintf(stderr, "\n"); printf("The executed time of %d data by Bubble sort is %.5f sec.\n", N, second() - start); ptr->flag[PARENT] = OFF; // 計算状態が終了 kill(ptr->id_number[PARENT], SIGCONT); } } if (shmdt(shmaddr) == -1) { perror("Shared menory closed"); exit(1); } return 0; } /* バブルソート */ void bubble_sort(int d[], int n) { int i, j, temp; for (i = 0; i < n - 1; i++) { for (j = n - 1; j > i; j--) { if (d[j - 1] > d[j]) { temp = d[j]; d[j] = d[j - 1]; d[j - 1]= temp; } } } } /* 稼働時間測定 */ double second() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + tv.tv_usec / 1.0e6; } /* 何もしないシグナル処理関数 */ void handler(int dummy) { ; }

参考URL:
www.xfile09.com/fig/algo1.pdf
回答No.4

>実行ファイル内で同時に二つの違う動作をさせることは可能なのでしょうか? これはすでに回答にあるとおり可能。 シングルコアCPUでは「マルチタスク」とは言っても「同時」ではなく短い時間で切り替えながら処理しているため「見かけ上」同時のように見えているだけ。 「完全な並列化」を行うためには、CPUが複数必要(マルチコアCPU)。 (ちなみにハイパースレッディングは、マルチコアよりの技術) 但し、 >並列処理はfor文などの単調な処理を並列処理にすることで実行を早くするということがわかったのですが、 コレは理解が不十分。 並列化できるのは「単調な処理」ではなく、「相互に依存関係がない処理」。 複雑な処理でも影響を及ぼさなければ一切問題は発生しない。 たとえば、ある動作を行うために 入力を「モジュールA」で処理し、その結果を「モジュールB」に渡す必要がある場合は並列化はできない。 入力1を「モジュールX」で処理し、入力2を「モジュールY」で処理する。この二つの処理結果を「モジュールZ」で利用するような場合なら、 「モジュールX」と「モジュールY」には依存関係がないため並列化は可能。

noname#140045
noname#140045
回答No.3

No.2です。 ゴメンなさい。質問の趣旨と違っていました。

noname#140045
noname#140045
回答No.2

やり方としては「マルチタスク」による方法と「スレッド」による方法があります。 スレッドは、サブルーチンを呼び出すようにして用います。 マルチタスクは、もう1つのプロセスとして自分自身を呼び出すのですが、わかってしまえばやり方は1通りなのでさほど難しくありません。 UNIX(Linux)の場合は、スレッドでもマルチタスクでもどちらでやっても処理速度はさほど変わらないため、マルチタスクでやるのが一般的です。 Windowsは、スレッドでやるのが一般的です。 ちなみに、マルチタスクの関数は、fork()ですので、これで検索すればいいかと思います。 スレッドの関数は忘れました。あしからず。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

可能か不可能か、で言えば「可能」です。 やり方は、コンパイラ、CPU、OS等によって違うので、簡単には説明できません。 また、並列処理することで、逐次処理では起らない問題が発生することがあります。(デッドロック、ライブロック等) これも、まともに説明すると本一冊書ける内容なので省略します。 forループを並列処理する簡単な方法は、OpenMP対応コンパイラを使用して、#pragma omp parallel for を使用することかな、と思います。 詳しくは OpenMP で検索してください

関連するQ&A

  • 並列処理プログラム

    並列処理について。 画像imageの値が0より大きい場合に、managerを実行しますが、managerの計算時間が長いです。 そこで、4つのコアでpthreadにより、並列処理をさせたいんですが、 どのようにプログラムを書けばいいかすみませんが教えてください。 あるボクセルを計算中に、次のボクセルを計算するようなプログラム。。。 for (int z=0; z<32; z++){  for (int y=0; y<32; y++){   for (int x=0; x<32; x++){    if(image(x,y,z) > 0){     total += manager(x,y,z);    }   }  } }

  • 流れ図からプログラムに直してください!【C言語】

    その流れ図をC言語のプログラムに直してくれませんか? 処理2はscanf(..);って感じの内容です。 入口 処理1 for(処理2; 判断; 処理4){ 処理3 } 出口 って感じかなって思ったんですが、for文の中にscanfの文を入れてもいいのかわからずに悩んでます。 ループ文なのでwhile文、for文、do..while文のどれかかな?って思ったんですが違う気もして、わかるかたいらっしゃいませんか?

  • C言語のプログラムの質問です

    C言語で負の値が入力されたときに処理を終了する条件でキーボードから繰り返し入力するためにはどのようなプログラムにしたらいいですか? (FOR文を使い、FOR文の繰り返し条件を入れないで繰り返す)

  • C言語での並列化について

    visual C++ 2010 expressで並列化のコードを書きたいのですが、 include ファイルを開けません。'omp.h': No such file or directoryとなり、実行できません。 どなたか解決策教えてください。 [OpenMPのサポート]は[はい]に変更しています。

  • C言語 (繰り返し処理-for文)

    C言語で繰り返し処理のfor文について質問ですが int counter ; for (counter = 1; counter <= 5; counter++)  { puts("繰り返し処理です") ; } の[counter++]の意味を教えてください

  • 並列処理について

    今現在Perlの並列処理について勉強しているのですが、分からない点があるのでご教授願います。 重並列が可能となるプログラムを作りたいと思い、以下のプログラムを作成しました。countには並列数(例えば3並列にしたいならば3)が入っています。これで重並列ができたと思ったのですが、よくよく考えてみると、このプログラムだと一つ目の子プロセスが終わらなければ、二つ目、三つ目の子プロセスが始まらないということに気付きました。同時に複数のプロセスを実行させるにはどのようなプログラムにすればよいでしょうか。お願いします。 while($count--){ $pid = fork; if(!defined $pid){die "fork failed";} elsif(!$pid){ &process;#子プロセス exit; } } wait; ・・・・・・#親プロセス

  • C言語のプログラムについて

    C言語のプログラムについて 3桁の自然数の中で、自分自身を含めた約数が奇数になるものがいくつあるかを求めるプログラムを作りたいのですが、swich文を使って、6通りの方法で出そうとしていまして、 while 文、 for文、 do while文に加え、 for文のを、1つの関数として独立させたもの、 さらに、for文のを重ループ部分のそれぞれのループに対応して、2つの関数として独立させたもの、 そして、この2つの関数のどちらともをループを用いずに再帰呼び出しを用いたもの の6通りで出したいのですが、swich文を使うところは自力でできたのですが、あとの6つそれぞれのプログラムの組み方がわかりません。 教えていただけないでしょうか?ややこしい書き方をしてすいません・・・。

  • C言語での置換処理について

    引数で指定されたディレクトリ配下のファイル全てに置換処理を行う 処理をC言語で作成したいと考えています。 ディレクトリ配下には、最大で100MB位のファイルが約100件存在する 想定です。 (ファイルのサイズ、件数は実行毎に異なります。) そこで2点ほど教えていただきたいことがあります。 1.基本的に、UNIXコマンドのtrコマンドでで置換するより、C言語で   全てのファイルを開き1行ずつ、「置換文字列のチェック」→   「置換文字列が存在すれば置換」→「ファイル書込み」と行った   ほうが早いものでしょうか?   (trコマンドを実行したところ、10分待っても処理が完了しませんでした。) 2.C言語にてディレクトリ配下のファイル名を取得し、ファイルの   件数分ループさせるにはどのようにすればよいのでしょうか?   execコマンドにて「ls -l test.txt | awk '{print $○}'」   (ファイル名のみ取得)の結果をファイルに出力し、そのファイル   からファイル名を取得し、EOFになるまでループすることで出来る   と思いますが、この方法は一般的でしょうか?   出来れば余計なファイルは、作成したくないと考えています。 ご回答の方、よろしくお願いします。

  • C言語でプログラムを書いています

    C言語でプログラムを書いています コンパイルに成功し、実行すると 「****.exeは動作を停止しました」 というエラーが出て、実行が強制終了されてしまいます このエラーはどのような場合に出るものであって、その解決法などご存知の方がいたら 教えていただきたいと思います 解説が載っているHPのURLでも構いませんので、よろしくお願いします

  • C言語プログラム

    C言語プログラム ある数を入力して、入力された数を一辺とする図形を描くプログラムを作りたいんです。 分かりやすくすると、 入力された数が5だった時、画面には ***** ***** ***** ***** ***** ↑こう出力させたいんです。 四角だけじゃなくて、 * ** *** **** ***** ↑こういう三角とか、逆三角とか、 *        * **     *** ***  ***** **     *** *        * こんなかんじでいろんな形を描けるようにしたいんです。 C言語で、for文の二重ループを使うようにとのことなんですが、 どうすればいいでしょうか。 こういうのってズルですけど、何かヒントでも貰えればと思っています...。

専門家に質問してみよう