I am trying to generate pgm image with a Buddhabrot fractal, in parallel, using pthreads and the master-slave model. From tests, I can see that the program starts the model with the right parallel mode, but it seems to be inside an infinite loop. The problem is that I can't see which one is the problem. Can someone give me a light about it? Thank you.
#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;
}
It seems like the problem is that you are assigning -1
as a magic number to next
, meaning "not yet initialized by the master". However, it's a possible legitimate value, because you calculate next
like this:
next = -2.0+i*dt;
Because dt
is 0.001, next
will be equal to -1 when i
is 1000, and since i
loops to 4000 (4.0/dt
), it will happen before the loop ends. Then you'll get stuck in an infinite loop because your slave thread is waiting for a value other than -1, so never sets condM
, so pthread_cond_wait(&condM, &mutex);
never returns in the master, so i
never increments.
Change your magic number from -1
to something outside the range of possible values for next
(e.g. -100
), or else use another mechanism.