Buddhabrot 分形与 pthread
Buddhabrot fractal with pthread
我正在尝试使用 pthreads 和主从模型并行生成带有 Buddhabrot 分形的 pgm 图像。从测试中,我可以看到程序以正确的并行模式启动模型,但它似乎处于无限循环中。问题是我看不出是哪一个有问题。有人可以告诉我吗?谢谢。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#define N_SLAVES 3
double next = -1;
int i = 0, nColumns = 2048, nLines = 2048, ite = 600;
double y, dt = 0.001;
int completedIterations;
pthread_mutex_t mutex;
pthread_cond_t condM;
pthread_cond_t condE;
typedef struct {
int x;
int y;
} int2;
typedef struct{
double x;
double y;
} double2;
int2 coordinatesConversion( double x,double y, int nColumns,int nLines){
int2 ret;
int2 retError;
retError.x=-1;
retError.y=-1;
ret.x=round(((2.0+x)/3.5) *((double)(nColumns-1)));
ret.y=round(((1.5+y)/3.5) *((double)(nLines-1)));
if(ret.x<0 || ret.x>=nColumns) return retError;
if(ret.y<0 || ret.y>=nLines) return retError;
return ret;
}
int printMatrixToFilePGM(float **mat,int tamx, int nLines, char *srcFile){
printf("First\n");
FILE *arq=fopen(srcFile,"w");
int cont, cont2;
float min,max;
min=mat[0][0];
max=mat[0][0];
for(cont=0;cont<nLines;cont++){
for(cont2=0;cont2<tamx;cont2++){
if(min>mat[cont][cont2]) min=mat[cont][cont2];
if(max<mat[cont][cont2]) max=mat[cont][cont2];
}
}
max=max*0.35;
float delta=max-min;
fprintf(arq,"P2 \n");
fprintf(arq,"#something \n");
fprintf(arq,"%d\n%d \n",tamx,nLines);
fprintf(arq,"255\n");
for(cont=0;cont<nLines;cont++){
for(cont2=0;cont2<tamx;cont2++){
int valpixel=((mat[cont][cont2]-min)/delta)*255.0f;
if(valpixel>255) valpixel=255;
fprintf(arq,"%d \n", valpixel);
}
}
fclose(arq);
}
float** mallocFloatMatrix(int tamx, int nLines, float defaultValueOfTheElementsAtMatrix){
float **errorCodeReturn=0x0;
float **mat;
int i,j;
int condErrorMalloc=0;
mat=malloc(sizeof(float *)*nLines);
if(mat==0x0) return errorCodeReturn;
for(i=0;i<tamx;i++)
mat[i]=malloc(sizeof(float )*tamx);
for(i=0;i<tamx;i++){
if(mat[i]==0x0){
condErrorMalloc=1;
break;
}
}
if(condErrorMalloc==0){
return mat;
}
for(i=0;i<nLines;i++){
for(j=0;j<tamx;j++)
mat[i][j]=defaultValueOfTheElementsAtMatrix;
}
for(i=0;i<tamx;i++)
if(mat[i]!=0x0) free(mat[i]);
free(mat);
return errorCodeReturn;
}
void freeFloatMatrix(float **mat,int tamx, int nLines){
int i;
for(i=0;i<nLines;i++){
if(mat[i]!=0x0) free(mat[i]);
}
free(mat);
}
int iteration(double x,double y, int nColumns,int nLines, int ite,int2 *iterationPath){
int cont;
int condInvalidPointer=1;
double2 z;
z.x=0.0;
z.y=0.0;
double2 c;
c.x=x;
c.y=y;
double2 zt;
for(cont=0;cont<ite;cont++){
zt.x=((z.x*z.x)-(z.y*z.y))+c.x;
zt.y=(2.0*(z.x*z.y))+c.y;
z=zt;
if(((z.x*z.x)+(z.y*z.y))>4.0){
if(cont>100)
condInvalidPointer=0;
break;
}
iterationPath[cont]=coordinatesConversion(z.x,z.y,nColumns,nLines);
}
if(condInvalidPointer)
return 0;
return cont;
}
void *master(void *param){
printf("Second\n");
int size = round(4.0/dt);
int i;
int progress = 0;
for(i = 0; i < size; i++){
next = -2.0+i*dt;
pthread_mutex_lock(&mutex);
pthread_cond_signal(&condE);
pthread_cond_wait(&condM, &mutex);
pthread_mutex_unlock(&mutex);
// progress++;
// if(progress%100 ==0)//print at screen information about progrees of the operation
// printf("2 - %lf \n", next);
}
}
void *slave(void *param){
int size = round(4.0/dt);
printf("Third\n");
int k;
float **mat = mallocFloatMatrix(nColumns, nLines, 0.0f);
if(mat == 0x0) return 0;
while(1){
pthread_mutex_lock(&mutex);
if(i >= size){
pthread_mutex_unlock(&mutex);
pthread_exit(0);
}
i++;
while(next == -1){
pthread_cond_signal(&condM);
pthread_cond_wait(&condE, &mutex);
}
double x = next;
next = -1;
pthread_cond_signal(&condM);
pthread_mutex_unlock(&mutex);
for(y=-2.0;y<2.0;y=y+dt){
int2* iterationPath = (int2 *)malloc(sizeof(int2) * ite);
if(iterationPath==0x0) return 0x0;
completedIterations = iteration(x, y, nColumns, nLines, ite, iterationPath);
for(k = 0; k < completedIterations; k++){
if(iterationPath[k].x!=-1 && iterationPath[k].y!=-1)//test if a point z in the iteration k may be normalized to coordinates at matrix mat.
mat[iterationPath[k].x][iterationPath[k].y] = mat[iterationPath[k].x][iterationPath[k].y]+1.0f;//increments a point in matrix, this point is pointed by z with z points normalized.
}
free(iterationPath);
}
}
printMatrixToFilePGM(mat,nColumns,nLines,"saida3.pgm");
freeFloatMatrix(mat,nColumns,nLines);
}
int main(void){
printf("Main\n");
int i, j, k;
pthread_t master_t;
pthread_t slave_t[N_SLAVES];
pthread_create(&master_t, NULL, master, NULL);
for(i = 0; i < N_SLAVES; i++)
pthread_create(&slave_t[i], NULL, slave, NULL);
pthread_exit(0);
return 0;
}
问题似乎是您将 -1
作为幻数分配给 next
,意思是 "not yet initialized by the master"。但是,这是一个可能的合法值,因为您可以这样计算 next
:
next = -2.0+i*dt;
因为dt
为0.001,当i
为1000时next
等于-1,而i
循环到4000(4.0/dt
), 它会在循环结束之前发生。然后你会陷入无限循环,因为你的从属线程正在等待-1以外的值,所以永远不要设置condM
,所以pthread_cond_wait(&condM, &mutex);
永远不会在主线程中设置returns,所以i
从不递增。
将您的幻数从 -1
更改为 next
可能值范围之外的值(例如 -100
),或者使用其他机制。
我正在尝试使用 pthreads 和主从模型并行生成带有 Buddhabrot 分形的 pgm 图像。从测试中,我可以看到程序以正确的并行模式启动模型,但它似乎处于无限循环中。问题是我看不出是哪一个有问题。有人可以告诉我吗?谢谢。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#define N_SLAVES 3
double next = -1;
int i = 0, nColumns = 2048, nLines = 2048, ite = 600;
double y, dt = 0.001;
int completedIterations;
pthread_mutex_t mutex;
pthread_cond_t condM;
pthread_cond_t condE;
typedef struct {
int x;
int y;
} int2;
typedef struct{
double x;
double y;
} double2;
int2 coordinatesConversion( double x,double y, int nColumns,int nLines){
int2 ret;
int2 retError;
retError.x=-1;
retError.y=-1;
ret.x=round(((2.0+x)/3.5) *((double)(nColumns-1)));
ret.y=round(((1.5+y)/3.5) *((double)(nLines-1)));
if(ret.x<0 || ret.x>=nColumns) return retError;
if(ret.y<0 || ret.y>=nLines) return retError;
return ret;
}
int printMatrixToFilePGM(float **mat,int tamx, int nLines, char *srcFile){
printf("First\n");
FILE *arq=fopen(srcFile,"w");
int cont, cont2;
float min,max;
min=mat[0][0];
max=mat[0][0];
for(cont=0;cont<nLines;cont++){
for(cont2=0;cont2<tamx;cont2++){
if(min>mat[cont][cont2]) min=mat[cont][cont2];
if(max<mat[cont][cont2]) max=mat[cont][cont2];
}
}
max=max*0.35;
float delta=max-min;
fprintf(arq,"P2 \n");
fprintf(arq,"#something \n");
fprintf(arq,"%d\n%d \n",tamx,nLines);
fprintf(arq,"255\n");
for(cont=0;cont<nLines;cont++){
for(cont2=0;cont2<tamx;cont2++){
int valpixel=((mat[cont][cont2]-min)/delta)*255.0f;
if(valpixel>255) valpixel=255;
fprintf(arq,"%d \n", valpixel);
}
}
fclose(arq);
}
float** mallocFloatMatrix(int tamx, int nLines, float defaultValueOfTheElementsAtMatrix){
float **errorCodeReturn=0x0;
float **mat;
int i,j;
int condErrorMalloc=0;
mat=malloc(sizeof(float *)*nLines);
if(mat==0x0) return errorCodeReturn;
for(i=0;i<tamx;i++)
mat[i]=malloc(sizeof(float )*tamx);
for(i=0;i<tamx;i++){
if(mat[i]==0x0){
condErrorMalloc=1;
break;
}
}
if(condErrorMalloc==0){
return mat;
}
for(i=0;i<nLines;i++){
for(j=0;j<tamx;j++)
mat[i][j]=defaultValueOfTheElementsAtMatrix;
}
for(i=0;i<tamx;i++)
if(mat[i]!=0x0) free(mat[i]);
free(mat);
return errorCodeReturn;
}
void freeFloatMatrix(float **mat,int tamx, int nLines){
int i;
for(i=0;i<nLines;i++){
if(mat[i]!=0x0) free(mat[i]);
}
free(mat);
}
int iteration(double x,double y, int nColumns,int nLines, int ite,int2 *iterationPath){
int cont;
int condInvalidPointer=1;
double2 z;
z.x=0.0;
z.y=0.0;
double2 c;
c.x=x;
c.y=y;
double2 zt;
for(cont=0;cont<ite;cont++){
zt.x=((z.x*z.x)-(z.y*z.y))+c.x;
zt.y=(2.0*(z.x*z.y))+c.y;
z=zt;
if(((z.x*z.x)+(z.y*z.y))>4.0){
if(cont>100)
condInvalidPointer=0;
break;
}
iterationPath[cont]=coordinatesConversion(z.x,z.y,nColumns,nLines);
}
if(condInvalidPointer)
return 0;
return cont;
}
void *master(void *param){
printf("Second\n");
int size = round(4.0/dt);
int i;
int progress = 0;
for(i = 0; i < size; i++){
next = -2.0+i*dt;
pthread_mutex_lock(&mutex);
pthread_cond_signal(&condE);
pthread_cond_wait(&condM, &mutex);
pthread_mutex_unlock(&mutex);
// progress++;
// if(progress%100 ==0)//print at screen information about progrees of the operation
// printf("2 - %lf \n", next);
}
}
void *slave(void *param){
int size = round(4.0/dt);
printf("Third\n");
int k;
float **mat = mallocFloatMatrix(nColumns, nLines, 0.0f);
if(mat == 0x0) return 0;
while(1){
pthread_mutex_lock(&mutex);
if(i >= size){
pthread_mutex_unlock(&mutex);
pthread_exit(0);
}
i++;
while(next == -1){
pthread_cond_signal(&condM);
pthread_cond_wait(&condE, &mutex);
}
double x = next;
next = -1;
pthread_cond_signal(&condM);
pthread_mutex_unlock(&mutex);
for(y=-2.0;y<2.0;y=y+dt){
int2* iterationPath = (int2 *)malloc(sizeof(int2) * ite);
if(iterationPath==0x0) return 0x0;
completedIterations = iteration(x, y, nColumns, nLines, ite, iterationPath);
for(k = 0; k < completedIterations; k++){
if(iterationPath[k].x!=-1 && iterationPath[k].y!=-1)//test if a point z in the iteration k may be normalized to coordinates at matrix mat.
mat[iterationPath[k].x][iterationPath[k].y] = mat[iterationPath[k].x][iterationPath[k].y]+1.0f;//increments a point in matrix, this point is pointed by z with z points normalized.
}
free(iterationPath);
}
}
printMatrixToFilePGM(mat,nColumns,nLines,"saida3.pgm");
freeFloatMatrix(mat,nColumns,nLines);
}
int main(void){
printf("Main\n");
int i, j, k;
pthread_t master_t;
pthread_t slave_t[N_SLAVES];
pthread_create(&master_t, NULL, master, NULL);
for(i = 0; i < N_SLAVES; i++)
pthread_create(&slave_t[i], NULL, slave, NULL);
pthread_exit(0);
return 0;
}
问题似乎是您将 -1
作为幻数分配给 next
,意思是 "not yet initialized by the master"。但是,这是一个可能的合法值,因为您可以这样计算 next
:
next = -2.0+i*dt;
因为dt
为0.001,当i
为1000时next
等于-1,而i
循环到4000(4.0/dt
), 它会在循环结束之前发生。然后你会陷入无限循环,因为你的从属线程正在等待-1以外的值,所以永远不要设置condM
,所以pthread_cond_wait(&condM, &mutex);
永远不会在主线程中设置returns,所以i
从不递增。
将您的幻数从 -1
更改为 next
可能值范围之外的值(例如 -100
),或者使用其他机制。