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),或者使用其他机制。