如何修复关于Mandelbrot集的Pthreads代码?

时间:2013-04-23 11:48:12

标签: c image pthreads set mandelbrot

我有以下关于计算和创建Mandelbrot集图片的Pthreads代码。我在C中的代码工作正常,它很好地打印出结果图片。关键是使用下面的代码,我能够编译代码并执行它。之后,如果我尝试在Gimp中查看生成的.ppm文件,它就无法打开它。我想我在代码中做错了。如果有人能帮助我,我会很高兴。

// mandpthread.c
// to compile: gcc mandpthread.c -o mandpthread -lm -lrt -lpthread
// usage: ./mandpthread <no_of_iterations> <no_of_threads> > output.ppm

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <assert.h>
#include <pthread.h>

typedef struct {
    int r, g, b;
} rgb;

int NITERATIONS, NTHREADS;
rgb **m;

void color(rgb **m, int x, int y, int red, int green, int blue)
{
    m[y][x].r = red;
    m[y][x].g = green;
    m[y][x].b = blue;
}

void mandelbrot(int tid)
{
    int w = 600, h = 400, x, y; 
    // each iteration, it calculates: newz = oldz*oldz + p, 
    // where p is the current pixel, and oldz stars at the origin
    double pr, pi;                   // real and imaginary part of the pixel p
    double newRe, newIm, oldRe, oldIm;   // real and imaginary parts of new and old z
    double zoom = 1, moveX = -0.5, moveY = 0; // you can change these to zoom and change position

    int start = tid * NITERATIONS/NTHREADS;
    int end = (tid+1) * (NITERATIONS/NTHREADS) - 1;

    //loop through every pixel
    for(y = 0; y < h; y++) {
        for(x = 0; x < w; x++) {
            // calculate the initial real and imaginary part of z, 
            // based on the pixel location and zoom and position values
            pr = 1.5 * (x - w / 2) / (0.5 * zoom * w) + moveX;
                pi = (y - h / 2) / (0.5 * zoom * h) + moveY;
                newRe = newIm = oldRe = oldIm = 0; //these should start at 0,0
                // i will represent the number of iterations
                int i;
                // start the iteration process
                for(i = start; i <= end; i++) {
                        // remember value of previous iteration
                        oldRe = newRe;
                        oldIm = newIm;
                        // the actual iteration, the real and imaginary part are calculated
                        newRe = oldRe * oldRe - oldIm * oldIm + pr;
                        newIm = 2 * oldRe * oldIm + pi;
                        // if the point is outside the circle with radius 2: stop
                        if((newRe * newRe + newIm * newIm) > 4) break;
                }

                if(i == NITERATIONS)
                color(m, x, y, 0, 0, 0); // black
            else
            {
                // normalized iteration count method for proper coloring
                double z = sqrt(newRe * newRe + newIm * newIm);
                int brightness = 256. * log2(1.75 + i - log2(log2(z))) / log2((double)NITERATIONS);
                color(m, x, y, brightness, brightness, 255);
            }

            }
    }

}

// worker function which will be passed to pthread_create function
void *worker(void *arg)
{
    int tid = (int)arg;
    mandelbrot(tid);
}


int main(int argc, char *argv[])
{
    pthread_t* threads;
    int i, j, rc;

    if(argc != 3)
    {
        printf("Usage: %s <no_of_iterations> <no_of_threads> > output.ppm\n", argv[0]);
        exit(1);
    }

    NITERATIONS = atoi(argv[1]);
    NTHREADS = atoi(argv[2]);
    threads = (pthread_t*)malloc(NTHREADS * sizeof(pthread_t));

    m = malloc(400 * sizeof(rgb *));
    for(i = 0; i < 400; i++)
        m[i] = malloc(600 * sizeof(rgb));

    // declaring the needed variables for calculating the running time
    struct timespec begin, end;
    double time_spent;

    // starting the run time
    clock_gettime(CLOCK_MONOTONIC, &begin);

    printf("P6\n# AUTHOR: ET\n");
    printf("%d %d\n255\n",600,400);

    for(i = 0; i < NTHREADS; i++) {
        rc = pthread_create(&threads[i], NULL, worker, (void *)i);
        assert(rc == 0); // checking whether thread creating was successfull
    }

    for(i = 0; i < NTHREADS; i++) {
        rc = pthread_join(threads[i], NULL);
        assert(rc == 0); // checking whether thread join was successfull
    }

    // printing to file
    for(i = 0; i < 400; i++) {
        for(j = 0; j < 600; j++) {
            fputc((char)m[i][j].r, stdout);
            fputc((char)m[i][j].g, stdout);
            fputc((char)m[i][j].b, stdout);
        }
    }

    // ending the run time
    clock_gettime(CLOCK_MONOTONIC, &end);

    // calculating time spent during the calculation and printing it
    time_spent = end.tv_sec - begin.tv_sec;
    time_spent += (end.tv_nsec - begin.tv_nsec) / 1000000000.0;
    fprintf(stderr, "Elapsed time: %.2lf seconds.\n", time_spent);

    for(i = 0; i < 400; i++)
        free(m[i]);
    free(m);

    free(threads);

    return 0;
}

1 个答案:

答案 0 :(得分:1)

最新版本的代码适用于100次迭代和1个线程。

enter image description here

执行两个线程失败,因为ppm文件每个线程有一个标头。

如果删除其中一个标题,图像会加载,但颜色会关闭,图像中会出现毛刺。

enter image description here