Search code examples
cpthreadsmutexmaster-slavefractals

Buddhabrot fractal with pthread


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;
}

Solution

  • 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.