みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

並列処理についてですが、

並列処理についてですが、

SCOREという並列環境を構築するソフトで、4つのPC(CPU:Quad Core)を、並列化させ、
ある逐次プログラム(C言語、ラプラス方程式を差分法で解くプログラムですがプログラム内容はあまり関係ないので、あるプログラムとさせていただきます)を並列処理させたところ、

1つのPCで、4つのプロセッサを使用し、合計4ノードで並列処理を行った場合と、・・・(1)
4つのPCで各PC1台につき1つのプロセッサずつ、合計4ノードで並列処理を行った場合では、・・・(2)

同じ4ノードであるにかかわらず、
(2)がノード数に比例的に演算性能が良くなることに対して、
(1)の場合、ノード数が増えても関数log(x)(雰囲気です)をグラフにしたような形で、演算性能がうまく良くなりません

このような質問を以前したところ、

・スレッド切り替えのオーバーヘッドが影響しているのではないか

・実行環境が違うことと、ひとつのプロセスですべてのコアを占有する thread はコアを2個使えば2倍、3個使えば3倍それぞれ速くはならない。一方、PCを組み合わせて使う場合、それは完全に独立しており、データ並列のために分割されて計算量が縮小された分、PC組み合わせ数にほぼ比例して速くなる。

という回答をいただくことができました。
なんとなくで意味は分かるのですが、何卒PC初心者なもので、あまり理解することができません。



ここからが質問です。


・「スレッド切り替え」とは一体どういったものなんでしょうか

・いただいた回答で、「ひとつのプロセスですべてのコアを占有するスレッド」とはどういうことでしょうか

このことについて教えていただきたいです。スレッドとは、など部分部分での単語は調べてみましたが、
どういったように動いているのかが分かっていないせいか、上記質問のようなことが分かりません。

回答をせっかくいただいたのに自分の語彙力のせいで度重なる質問をさせていただくことを申し訳なく思いますが、みなさん回答の方よろしくおねがいします。

投稿日時 - 2010-01-21 18:43:05

QNo.5611436

すぐに回答ほしいです

質問者が選んだベストアンサー

http://oshiete1.goo.ne.jp/qa5587724.html
ではどうもです。

 スレッドは当初、CPUのクロックが速過ぎてメモリが追いつかないためにwaitを沢山いれて動いていました。waitはその名のとおり、待つだけで何もしていません。それではもったいないと、その空いた時間を裏で行う方法を取り入れました。それが threadです。Intelでは30186(50MHz)当たりからwaitの比重が大きくなって来たと記憶しています。
 現在はそれがパソコンの主流ですが、Mac OSXではコアの負荷状態を目視できるアクティビティモニタがあるため、すべてのコアを占有するところを確認することができます。↑の「#define THREAD_NUM 3」を1~4に変えてモニタを見ながら実験してみるとthreadの特性を知ることができます(琉球大学、九州大学、京都産業大学、電気通信大学、東京大学の学生の方は学内で実験できる環境にあります)。
 同じことがプロセスの並列起動、並列処理を行わせることで実現できます。巷ではセマフォやミューテックスが必須であって、有り得ない話と思われていますが、それはデマです。これも目て確認してみてください。一応、threadを使わないオーソドックスな並列プロセスとした dual coreの場合の事例(2台並べたと同じ環境)を上げておきます。起動は「 ./a.out 」です。
www.xfile09.com/fig/algo1.pdf


/* Main program by Mac OSX
* file name: xxx.c
* compile: gcc xxx.c
* execution: ./a.out
*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <signal.h>
#include <errno.h>
#include "xxx3.h"

#define CODE 999/* 適当に変更のこと */

void pi_calc(double *);
void handler(int);

int main(void) {
int shmid;
void *shmaddr;
char command_line[64];
double pi;
struct timeval tv;
struct timezone tz;
double before, after;

/* 共有メモリの確保 */
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);

/* バックグランドで同時計算可に*/
ptr->flag[PARENT] = ON;// 子プロセス完了まで待つ
sprintf(command_line, "./xxx2 %d &", shmid);
if (system(command_line) != 0) {
perror("Shell command line");
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);

gettimeofday(&tv, &tz);
before = (double)tv.tv_sec + (double)tv.tv_usec * 1.0e-6;

/* 円周率の計算 */
pi_calc(&pi);// 共有メモリ:&ptr->shmem1

/* 計算終了まで待機(dead_lockの回避)
*作業継続入力後も子プロセスが出力中なら1秒休む。
*ただし出力が完了したならシグナル等で起こされる。
*/
while (ptr->flag[PARENT] != OFF)
sleep(1);

/* データ並列によるπ = 前半部分+後半部分 */
pi = pi + ptr->shmem2;// 共有メモリ:pi=ptr->shmem1+ptr->shmem2
printf("pi= %.11f\n", pi);

gettimeofday(&tv, &tz);
after = (double)tv.tv_sec + (double)tv.tv_usec * 1.0e-6;
fprintf(stderr, "%.3f sec\n", after - before);

/* 子プロセスのプログラム終了送信 */
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 pi_calc(double *sum) {
int i;
double step, temp;

step = 1.0 / (double)TIMES;
*sum = 0.0;

/* データ並列、前半部分を受け持つ */
for (i = 1; i <= (TIMES / DIVIDED); i++) {
temp = (i - 0.5) * step;
*sum += 4.0 / (1.0 + temp * temp);
}

*sum *= step;
}


/* 何もしないシグナル処理関数 */
void handler(int dummy){
;
}

----- ここまで -----

/* Other parallel processing program by Mac OSX
* file name: xxx2.c
* compile: gcc xxx2.c -o xxx2
* execution: Don't execute this program.
*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <signal.h>
#include <errno.h>
#include "xxx3.h"

void pi_calc(double *);
void handler(int);

int main(int argc, char *argv[]) {
int shmid;
void *shmaddr;

/* 親プロセスから受け継ぐ */
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();

/* シグナルハンドラー登録 */
signal(SIGCONT, handler);

/* 親プロセスに「スタンバイ ok!」を知らせる */
ptr->flag[PARENT] = OFF;
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);
pi_calc(&ptr->shmem2);
fprintf(stderr, "\n");
ptr->flag[PARENT] = OFF;
kill(ptr->id_number[PARENT], SIGCONT);
}
}

if (shmdt(shmaddr) == -1) {
perror("Shared menory closed");
exit(1);
}

return 0;
}

/* 円周率の計算 */
void pi_calc(double *sum) {
int i;
double step, temp;

step = 1.0 / (double)TIMES;
*sum = 0.0;

/* データ並列、後半部分を受け持つ */
for (i = (TIMES / DIVIDED) + 1; i <= TIMES; i++) {
temp = (i - 0.5) * step;
*sum += 4.0 / (1.0 + temp * temp);
}

*sum *= step;
}


/* 何もしないシグナル処理関数 */
void handler(int dummy){
;
}

----- ここまで -----

/* 共通事項リストアップ・定義等ヘッダーファイル
* file name: xxx3.h
*
*プロセス間での共通項を列挙し、不用意な間違いを少なくする。
*Cの線形構造を利用する。
*/

#define PROCS 3/* 全プロセス数 */
#define CHILD 1/* 子プロセス1 */
#define PARENT 0/* 親プロセス */
#define ON 1
#define OFF 0
#define TIMES 1000000000/* 1億回 */
#define DIVIDED 2/* dual core */


struct set1 {/* common variable */
double shmem1, shmem2;/* data buffer */
signed char flag[PROCS];/* condition flag */
pid_t id_number[PROCS];/* id code */
} *ptr;

投稿日時 - 2010-01-24 00:29:19

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(1)

あなたにオススメの質問