並列処理プログラムの作成方法

このQ&Aのポイント
  • 画像の値が0より大きい場合に、managerを実行するための並列処理プログラムを作成する方法について
  • 4つのコアを使用してpthreadを利用し、並列処理を行うプログラムの書き方について
  • ボクセルを計算しながら次のボクセルを計算するプログラムの作成手順
回答を見る
  • ベストアンサー

並列処理プログラム

並列処理について。 画像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);    }   }  } }

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

  • ベストアンサー
  • salsberry
  • ベストアンサー率69% (495/711)
回答No.1

念のために確認ですが、たとえばmanager(x,y,3)の計算結果がmanager(x,y,9)の計算に影響を与えるようなことはないのですよね? 影響する場合には仕事の分割が難しくなるので。 基本的な手順はこんな感じです。 1) メインスレッドは4つの子pthreadをpthread_createで起動します。それぞれのidを0~3とします。 2) 子pthreadはそれぞれ下記の計算を行います。total[]は大域変数という想定です。 for (int z=id*8; z<id*8+8; z++){  for (int y=0; y<32; y++){   for (int x=0; x<32; x++){    if(image(x,y,z) > 0){     total[id] += manager(x,y,z);    }   }  } } 3) メインスレッドは全ての子pthreadが終了するのをpthread_joinで待ちます。 4) メインスレッドでtotal[0~3]の結果を合計します。 子スレッドのidを指定するにはpthread_createの第4引数を使って工夫すればいいでしょう。 子スレッドの計算結果もpthread_exitを使ってメインスレッドに返す方法がありますが、void*型だからといってうっかりローカル変数へのポインタを使ったりすると予期しないことが起きます(この点はpthread_createの第4引数も同じ)。 zの範囲を4つのスレッドに分割した例を示しましたが、扱うデータの形式によっては別の分け方をしたほうがキャッシュミスが減って速くなるかもしれないです。

wakate
質問者

お礼

ご返事ありがとうございます。 managerの結果は相互に影響しないので、上の方法でやってみます。 データの中身によっては、ある断面(z=10)しか値がない場合があるので x,yの範囲に分割してみまーす。

その他の回答 (1)

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

どんな環境でやってますか? OpenMP対応コンパイラ( VC++2005以降など)だとこんな書き方もできます #pragma omp parallel for reduction(+:total) 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);    }   }  } }

wakate
質問者

お礼

VC++2005 Academic Editionを使用しているので、 残念ながらOpenMPには未対応です。 しかし、OpenMPに関する情報ありがとうございます。

関連する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初心者なもので、あまり理解することができません。 ここからが質問です。 ・「スレッド切り替え」とは一体どういったものなんでしょうか ・いただいた回答で、「ひとつのプロセスですべてのコアを占有するスレッド」とはどういうことでしょうか このことについて教えていただきたいです。スレッドとは、など部分部分での単語は調べてみましたが、 どういったように動いているのかが分かっていないせいか、上記質問のようなことが分かりません。 回答をせっかくいただいたのに自分の語彙力のせいで度重なる質問をさせていただくことを申し訳なく思いますが、みなさん回答の方よろしくおねがいします。

  • 画像処理のプログラムについて

    初めまして、こんにちは C言語で画像処理のプログラミングについてご解答をお願いします 現在二値化した白黒バーコードに対して、ビット数埋め込みというものを行っています この画像に埋め込んだビットを、検出するプログラムを作成したいのですがどうしたらいいでしょうか? ソースコードは以下です int x,y,i,j; double Th = 128.0; /*2値化の際のしきい値 */ int x_StartPos, y_StartPos,x_EndPos,y_EndPos; /*バーコードが描画されている領域の座標 */ int num; y=0; while (y<biHeight){ x=0; while(x<biWidth){ if (Y[y][x]<Th) break; x++; } if (x < biWidth){ x_StartPos = x; y_StartPos = y; break; } y++; } if ((x_StartPos==0) && (y_StartPos==0)) { printf("画像中に黒領域が見つかりませんでした"); exit(-1); } x_EndPos=0; while (x<biWidth){ /*画面右までスキャンして、一番右端の黒のx座標を求める*/ if (Y[y][x] < Th)/* 黒い点であったら */ x_EndPos=x; x++; } if (x_EndPos==0) { printf(" バーコード右端が検出できませんでした\n"); exit(-1); } /*バーコード一番上のラインにおける、黒の画素の数を数える*/ x=y_StartPos; y=y_StartPos; num=0; //これまでに検出した黒画素の数 while(x<=x_EndPos){ if (Y[y][x] < Th) // 黒い点であったら num++; //黒画素数を +1 する x++; } *start_x= x_StartPos; *start_y= y_StartPos; *end_x = x_EndPos; *num_of_blackpixels =num; } void Embed_watermark(double Y[Y_SIZE][X_SIZE],double Y_out[Y_SIZE][X_SIZE], int sukasi[], int Length, int x_StartPos, int y_StartPos, int x_EndPos) { int x,y; int bitnum; double Th = 128.0; /*2値化の際のしきい値 */ for(y=0;y<biHeight;y++) //出力データに元データをコピー for(x=0;x<biWidth;x++) Y_out[y][x]=Y[y][x]; bitnum=0; //現在何番目のbitが埋め込み対象になっているのか x=x_StartPos; y=y_StartPos; //埋め込み開始 while(x<=x_EndPos){ if (Y_out[y][x]<Th){ //もし注目点が黒画素なら透かし埋め込み処理を行う printf("found! x=%d bitnum=%d\n",x,bitnum); if (sukasi[bitnum]==0){ // 「0」を埋め込むなら、該当画素を白くする Y_out[y][x]=255; } bitnum++; //埋め込み対象を次のビットにする } if (bitnum==Length) // もし全てのビットの埋め込み処理が終了したら break; x++; } printf("埋め込みが完了しました.埋め込み終了x座標=%d\n",x); } void main(void) { int Length = 20; // 埋め込む透かしのビット長 int suuchi[]={1,1,1,1,0,0,0,0,1,1,1,0,0,0,1,1,0,0,1,0}; //埋め込む透かしビット char *input="bar.bmp"; char *output="out.bmp"; /* 画像中のバーコードが書かれている左上端の座標 */ int x_StartPos; int y_StartPos; int x_EndPos;//バーコードx座標の終端 int Num_of_Blacks; //バーコードの横方向の黒画素数(=埋め込めるビット数の上限)

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

    明解C言語という書籍に 大きい方を表示するプログラム #include <stdio.h> int maxof(int x, int y) {  if (x > y)   return (x);  else   return (y); } int main(void) {  int na, nb;  puts("二つの整数を入力してください。");  printf("整数1:"); scanf("%d", &na);  printf("整数1:"); scanf("%d", &na);  printf("大きいほうの値は%dです。\n", maxof(na, nb));  return (0); } の関数maxofを利用し、 int max4(int w, int x, int y, int z) {  return (maxof(maxof(w, x), maxof(y, z))); } を挿入して変えれば四つの整数から最大値を求められるとのことですが、 コンパイルがうまくいきません。 関数maxofのwとx,yとzをそれぞれ比較し最大値を求めてさらにmaxof(w, x)とmaxof(y, z)を比較して最大値を求めるということですよね?ですので、 maxof(w, x) {  if (w > x)   return (w);  else   return (x); } maxof(y, z) {  if(y > z)   return (y);  else   return (z); を挿入しようとしたらmaxofはすでにありますというようなことが表示されてだめでした。 また、 int maxof(maxof(int w, int x), maxof(int y, int z)) { if (w > x)   return (w); if (w < x)   return (x); if (y > z)   return (y); if (y < z)   return (z); if (maxof(w, x) > maxof(y, z))   return (maxof(w, x)); if (maxof(w, x) < maxof(y, z))   return (maxof(y, z)); } としてみましたがやはりだめでした。 前のページの説明を読み返したりネットで調べてもわかりませんでした。 何がわからないのかがわからないのでもうお手上げです。 長くなってすいません プログラム例と説明をお願いします。

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

    三角形を判定するプログラムを作ったのですが直角三角形ができるはずがないのに直角三角形の判定が出てしまいます。簡単なことなのかもしれませんが自分ではわからなくなってしまったのでご指摘してもらいたいです。 #include<stdio.h> void tri(int x,int y,int z) { if((x*x==y*y+z*z)||(y*y==x*x+z*z)||(z*z==x*x+y*y)) { printf("これは直角三角形です。"); printf("これは三角形です。"); }else if((x+y>=z)||(x+z>=y)||(y+z>=x)) { printf("これは三角形ではありません。"); }else{ printf("これは三角形です。"); } } int main(void) { int e1,e2,e3; printf("3辺を入力してください"); scanf("%f,%f,%f",&e1,&e2,&e3); tri(e1,e2,e3); return(0); }

  • プログラム ファイル処理について

    プログラムの問題が解けなくて困っています。 visual C++ 2010 Express を使用しています。 (1)X,Yの範囲がそれぞれ-200から200の範囲で空間内に立体が書かれる ようにエクセルファイルにデータを入れたいのですが、その処理がうまくいきません。 (2)degreeの意味がわかりません。degree*PI(円周率)/180でradianなのですか? よろしくお願いします。 今、2次元平面上の座標値(x,y)に対し、(x2+y2)0.5を角度(degree) とした場合に、 下記の式によって定義されるポテンシャル値zの分布を考える z=30×(cos(√(x2+y2))+cos((3×√(x2+y2))) xとyの範囲を(-200<X<200)、(-200<Y<200)と設定してXとYの値を10ごとに増加させた場合のZの値を 以下のようなfor文を用いて計算し、 for(y=200.0;y>=-200.0;y=y-10.0){  for(x=-200.0;x<=200.0;x=x+10.0){  } } 同一のY座標値におけるZの値がカンマで区切られて並ぶテキストファイルを出力するプログラムを作成しなさい。 そのファイルをエクセルで開き(カンマ区切りで) 3次元グラフを表示させる. ヒント1: #include <math.h> を宣言することにより、数学関数 cos sin pow が使用可能となる。 ヒント2: sin cos の引数はラジアン単位で指定する必要があるため、円周率を用いて degree から radian を求めること

  • for 文における処理の改善(C言語プログラム)

    はじめまして。panicdjです。 いまCでプログラムを組んでいます。 環境はVC++ver6.0 Win32 Console Applicationです。 以下のプログラムを見てください。 #define X_MAX 10 #define Y_MAX 20 #define Z_MAX 5 int main(int argc , char ** argv) { int i, j, k; int aa[10][20][5]; for (i = 0; i < X_MAX; i ++) { for (j = 0; j < Y_MAX; j ++) { for (k = 0; k < Z_MAX; k ++) { aa[i][j][k] = 10.0; } } return 0; } 過去のスレッドでポインタ型によるアクセスを すれば、処理が高速になるとかかれていました。 自分は,for文による繰り返す処理ではなく, その「ポインタ型によるアクセス」を実装したいのです。 こんな私にアドバイスお願い致します。

  • 並列処理(SCore)

    並列処理(SCore) 自分はSCOREを用いて並列処理を行おうとしている初心者です。 [環境] ・CPU Intel Core2 Quad 2.83GHz ・メモリ 8GB ・スイッチングハブ FXG-08IMB(ギガビット) これをサーバー兼計算ホスト1台、計算ホスト3台の計4台でSCoreによって並列環境として接続しました。 ・使用したプログラムは、初期値を設定し、ラプラス方程式を逐次的に計算させるプログラムです。 ・並列処理を行うためのプログラムとして、MPIを使用しました。 いろいろなパターンでプログラムを実行した結果を図に貼り付けておきます。 クアッドコアなので、1PCで4ノード扱うことができています。 やや頭でっかちとなってしまいましたが、ここからが質問です。 [質問?] たとえば、1つのPCで、4ノードで並列処理を行った場合と、 4つのPCで各1ノードずつ、合計4ノードで並列処理を行った場合に、 4PCで1ノードずつを並列接続したほうが"約1.8倍"の演算性能を誇っているのはなぜでしょうか? [質問?] 今回は初期値を設定して、ラプラス方程式を解く逐次プログラムを使用しましたが、 プログラムによっては、質問?のような結果にならない場合もあるのでしょうか? もしあるなら、どのようなタイプのプログラムなら、1台で4ノード、4台で4ノードの演算性能がほとんど同じ程度になるのでしょうか? できれば、?も?も上記した環境を踏まえて回答していただけると幸いです。 申し訳ありませんが、初心者ということを分かって回答していただけると助かります。 面倒だとは思いますが、回答よろしくおねがいします。 [以下プログラム] この逐次プログラムをMPI関数によって並列処理可能にしたものが実際使用したプログラムです。 (文字数が足りなかったので、並列化する前の逐次プログラムをせめて載せておきます。) #include<math.h> #include<stdio.h> #include<sys/time.h> #define SIZE (1024*3 - 2) #define EPS 1.0e-1 double u[SIZE+2] [SIZE+2], uu[SIZE+2][SIZE+2]; double second() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + tv.tv_usec / 1000000.0; } void init(double u[SIZE+2][SIZE+2]) { int i,j; memset (u,0,sizeof(double)*(SIZE+2)*(SIZE+2)); for (i=1;i<=SIZE;i++) for(j=1;j<=SIZE;j++) u[i][j]=sin((j-1)/(SIZE*M_PI))+cos((j-1)/(SIZE*M_PI)); } int main() { double start,time,err; int i,j,iter=0; init(u); init(uu); start=second(); do{ {iter ++;} for(i=1;i<=SIZE;i++) for(j=1;j<=SIZE;j++) uu[i][j]=u[i][j]; for(i=1;i<=SIZE;i++) for(j=1;j<=SIZE;j++) u[i][j]=(uu[i-1][j]+uu[i+1][j]+uu[i][j-1]+uu[i][j+1])/4.0; {err=0.0;} for(i=1;i<=SIZE;i++) for(j=1;j<=SIZE;j++) err+=(uu[i][j]-u[i][j])*(uu[i][j]-u[i][j]); }while (err>EPS); time = second()-start; printf("time=%f seconds, iteration=%d,performance=%f MFLOPS\n", time,iter,(8.0*SIZE*SIZE*iter)/time/1.0e6); return 0; }

  • 画像処理

    初歩的な質問なんですが、この下のプログラムは画像全体にモザイクをかけているものですが、画像上の範囲を指定して、その範囲内の領域だけモザイクをかけるにはどうしたらいいでしょうか? void make_cmosaic_image() { int i,j,x,y,k; int bsz; /*ブロックサイズ*/ int bx,by; int bvaIR,bvaIG,bvaIB; /*ブロックの平均値*/ int pels; int X,Y; /*ピクセルの位置*/ printf("カラー画像のモザイク化\n"); pXdim2=pXdim1; pYdim2=pYdim1; printf("ブロックサイズを入力してください(1より大きい値):"); scanf("%d",&bsz); printf("ブロックサイズは%dである。",bsz); if(pXdim1 % bsz ==0) bx= pXdim1 / bsz; else bx=pXdim1 / bsz+1; if(pYdim1 % bsz ==0) by=pYdim1/bsz; else by=pYdim1/bsz+1; /*モザイク化する*/ for(j=0;j<by;j++) for(i=0;i<bx;i++){ /*ブロックごと に 計算する*/ /*各ブロックのピクセル平均値を計算する*/ bvaIR = bvaIG =bvaIB=0; pels=0; /*各ブロックのピクセル値の和を計算する*/ for(y=0;y<bsz;y++) for(x=0;x<bsz;x++){ /*現在のピクセルの位置を計算する*/ X=i*bsz+x; Y=j*bsz+y; /*この位置が有効であれば、和を計算する*/ if(X>=0 && X<pXdim1 && Y>=0 && Y<pYdim1){ pels++; /*和を計算する*/ bvaIR +=pimage1[0][Y][X]; bvaIG +=pimage1[1][Y][X]; bvaIB +=pimage1[2][Y][X]; } } bvaIR /=pels; bvaIG /=pels; bvaIB /=pels; /*計算した平均値を目的画像へ代入する*/ for(y=0;y<bsz;y++) for(x=0;x<bsz;x++){ X=i*bsz+x; Y=j*bsz+y; if(X>=0 && X<pXdim1 && Y>=0 && Y<pYdim1){ else pimage2[0][Y][X]=bvaIR; pimage2[1][Y][X]=bvaIG; pimage2[2][Y][X]=bvaIB; }  }  }  }

  • 並列処理について

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

  • ラベリング処理プログラム

    画像のラベリング処理プログラムを作っているんですが どうもうまく実行できません。よければ教えていただけないでしょうか。 #include<stdio.h> #include<stdlib.h> int column, row; unsigned char val[4] = {0,0,0,0}; unsigned char tmp[255]; int pos_y[4] = {-1, 0, 1, 0}; int pos_x[4] = {0, 1, 0, -1}; int i, j, x, y, label, level, label1; int label_count = 1; unsigned char *in, *out; void labeling_main(); void labeling_search(); void labeling_main() { for(i = 0; i < y; i++){ for(j = 0; j < x; j++){ printf("aaa\n"); if(out[i * x + j] == 255){ printf("bbb\n"); fflush(stdout); out[i * x + j] = label_count; labeling_search(label_count, i, j); label_count++; } } } } void labeling_search(int label_count, int x, int y) { for(i = 0; i < 4; i++){ if(out[(pos_y[i] + y) * x + (pos_x[i] + x)] == 255){ out[(pos_y[i] + y) * x + (pos_x[i] + x)] = label_count; labeling_search(label_count,(pos_y[i]+y),(pos_x[i]+x)); } } printf("ccc\n"); } int main(int argc, char *argv[]) { int result; int head, Magic; unsigned char *image, *in, *out, *res, *ros; FILE *fin, *fout; if(argc!=3){ printf("Usage : %s input output\n",argv[0]); exit(1); } fin = fopen(argv[1],"rb"); /* -------------------- ヘッダ取得ここから -------------------- */ fgets(tmp,255,fin); if(tmp[0]!='P') return 0; sscanf(tmp,"P%d",&Magic); if(Magic < 1 || Magic > 6) return 0; do fgets(tmp,255,fin); while(tmp[0]=='#'); sscanf(tmp,"%d %d",&x,&y); if(x < 1 || y < 1) return 0; fgets(tmp,255,fin); sscanf(tmp,"%d",&level); /* ヘッダの確認 */ printf("P%d\n",Magic); printf("%d %d\n",x,y); printf("%d\n",level); /* 画素の読み込み */ in = (unsigned char *)malloc(sizeof(unsigned char) *x*y); fread(in,sizeof(unsigned char),x*y,fin); fout = fopen(argv[2],"wb"); fprintf(fout,"P%d\n",Magic); fprintf(fout,"# My new PGM\n"); fprintf(fout,"%d %d\n",x, y); fprintf(fout,"%d\n",level); fwrite(out, sizeof(unsigned char),x*y, fout); out = (unsigned char *)malloc(sizeof(unsigned char) *x*y); //2値画像 for (i = 0; i < y; i++) { for (j = 0; j < x; j++){ if(in[i * x + j] > 120){ out[i * x + j] = 0; }else if(in[i * x + j] <= 120){ out[i * x + j] = 255; } } } labeling_main(); printf("Max label number:%d\n",label_count); free(in); free(out); fclose(fin); fclose(fout); } コンパイルは通るのですが実行するとlabeling_mainの if文でセグメンテーションが出てしまいます。

専門家に質問してみよう