私は、スレッドとミューテックスを含む C の小さなプロジェクトに取り組んでいます。私が取り組んでいるプログラムは、bmp メイジにフィルターを適用します。プロジェクトの目標は、このコマンド ラインを処理できるプログラムを実装することです。
$ ./filter -f filter1[,filter2[,...]] -t numThreads1[,numThreads2[,...]] input-folder output-folder
ここで、-f は適用するフィルター (「赤」、「青」、「緑」、「グレースケール」、「ぼかし」) であり、-t はフィルターごとに割り当てられたスレッドの数です。
これまでのところ、データ競合で立ち往生しているぼかしを除いて、すべて問題ありません(または、そう思います)。ぼかしフィルターは次のように機能します。
/* Add a Gaussian blur to an image using
* this 3X3 matrix as weights matrix:
* 0.0 0.2 0.0
* 0.2 0.2 0.2
* 0.0 0.2 0.0
*
* If we consider the red component in this image
* (every element has a value between 0 and 255)
*
* 1 2 5 2 0 3
* -------
* 3 |2 5 1| 6 0 0.0*2 + 0.2*5 + 0.0*1 +
* | |
* 4 |3 6 2| 1 4 -> 0.2*3 + 0.2*6 + 0.2*2 + -> 3.2
* | |
* 0 |4 0 3| 4 2 0.0*4 + 0.2*0 + 0.0*3
* -------
* 9 6 5 0 3 9
*
* The new value of the pixel (3, 4) is round(3.2) = 3.
*
* If a pixel is outside the image, we increment the central pixel weight by 0.2
* So the new value of pixel (0, 0) is:
* 0.2 * 0 + 0.2 * 9 + 0.2 * 6 + 0.2 * 9 + 0.2 * 9 = 6.6 -> 7
*/
問題は、このぼかしフィルターを使用して「チェス盤」画像でプログラムを実行すると、次のようになります。
$ ./filter -f blur -t 8 chess.bmp chessBlur.bmp
この画像を取得することを期待していますが、これを取得しています(「壊れた」行はランダムに異なります)
ミューテックスを使用してクリティカル セクションのロックとロック解除を行っていますが、ご覧のとおり、データ競合は依然として発生しています。フィルターに 2 語だけかけると、各スレッドに一度に 1 行ずつ、下から上へと順に表示されます。filter_blur の私のコードは次のとおりです。
int filter_blur(struct image *img, int nThread)
{
int error = 0;
int mod = img->height%nThread;
if (mod > 0)
mod = 1;
pthread_t threads[nThread];
pthread_mutex_t mutex;
args arguments[nThread];
struct image* img2 = (struct image*)malloc(sizeof(struct image));
memcpy(img2,img,sizeof(struct image));
error=pthread_mutex_init( &mutex, NULL);
if(error!=0)
err(error,"pthread_mutex_init");
int i = 0;
for (i=0; i<nThread; i++) {
arguments[i].img2 = img2;
arguments[i].mutex = &mutex;
}
int j = 0;
for (i=0; i<(img->height)/nThread + mod; i++) {
for (j=0; j<nThread; j++) {
arguments[j].img = img; arguments[j].line = i*nThread + j;
error=pthread_create(&threads[j],NULL,threadBlur,(void*)&arguments[j]);
if(error!=0)
err(error,"pthread_create");
}
for (j=0; j<nThread; j++) {
error=pthread_join(threads[j],NULL);
if(error!=0)
err(error,"pthread_join");
}
}
free(img2);
return 0;
}
void* threadBlur(void* argument) {
// unpacking arguments
args* image = (args*)argument;
struct image* img = image->img;
struct image* img2 = image->img2;
pthread_mutex_t* mutex = image->mutex;
int error;
int line = image->line;
if (line < img->height) {
int i;
error=pthread_mutex_lock(mutex);
if(error!=0)
fprintf(stderr,"pthread_mutex_lock");
for (i=0; i<img->width; i++) {
img->pixels[line * img->width +i] = blur(img2,i,line);
}
error=pthread_mutex_unlock(mutex);
if(error!=0)
fprintf(stderr,"pthread_mutex_unlock");
}
pthread_exit(NULL);
}
struct pixel blur(struct image* img2, int x, int y) {
double red = 0;
double green = 0;
double blue = 0;
red=(double)img2->pixels[y * img2->width + x].r/5.0;
green=(double)img2->pixels[y * img2->width + x].g/5.0;
blue=(double)img2->pixels[y * img2->width + x].b/5.0;
if (x != 0) {
red+=(double)img2->pixels[y * img2->width + x - 1].r/5.0;
green+=(double)img2->pixels[y * img2->width + x - 1].g/5.0;
blue+=(double)img2->pixels[y * img2->width + x - 1].b/5.0;
} else {
red+=(double)img2->pixels[y * img2->width + x].r/5.0;
green+=(double)img2->pixels[y * img2->width + x].g/5.0;
blue+=(double)img2->pixels[y * img2->width + x].b/5.0;
}
if (x != img2->width - 1) {
red+=(double)img2->pixels[y * img2->width + x + 1].r/5.0;
green+=(double)img2->pixels[y * img2->width + x + 1].g/5.0;
blue+=(double)img2->pixels[y * img2->width + x + 1].b/5.0;
} else {
red+=(double)img2->pixels[y * img2->width + x].r/5.0;
green+=(double)img2->pixels[y * img2->width + x].g/5.0;
blue+=(double)img2->pixels[y * img2->width + x].b/5.0;
}
if (y != 0) {
red+=(double)img2->pixels[(y - 1) * img2->width + x].r/5.0;
green+=(double)img2->pixels[(y - 1) * img2->width + x].g/5.0;
blue+=(double)img2->pixels[(y - 1) * img2->width + x].b/5.0;
} else {
red+=(double)img2->pixels[y * img2->width + x].r/5.0;
green+=(double)img2->pixels[y * img2->width + x].g/5.0;
blue+=(double)img2->pixels[y * img2->width + x].b/5.0;
}
if (y != img2->height - 1) {
red+=(double)img2->pixels[(y + 1) * img2->width + x].r/5.0;
green+=(double)img2->pixels[(y + 1) * img2->width + x].g/5.0;
blue+=(double)img2->pixels[(y + 1) * img2->width + x].b/5.0;
} else {
red+=(double)img2->pixels[y * img2->width + x].r/5.0;
green+=(double)img2->pixels[y * img2->width + x].g/5.0;
blue+=(double)img2->pixels[y * img2->width + x].b/5.0;
}
struct pixel pix = {(unsigned char)round(blue),(unsigned char)round(green),(unsigned char)round(red)};
return pix;
}
編集1:
@job が正しく推測したように、問題は構造体の memcpy が原因でした (構造体はコピーされましたが、構造体内のポインターは元の構造体要素を指していました)。私はミューテックスも削除しました(私の問題を解決できると思ったので、ミューテックスはここにありました。申し訳ありませんが、悪いです)今、私のプロジェクトは魅力的に機能しています(処理速度とスレッドを使用する必要性についてまだ話し合うことができますが) )。私が言ったように、これはプロジェクトであり、私の C クラスの大学プロジェクトです。目標はフィルターを並列化することです。したがって、スレッドが必要です。
ありがとう!