0

I have the following Pthreads code about calculating and creating a picture of the Mandelbrot set. My code in C works just fine and it prints the resulting picture nicely. The point is that using the below code, I am able to compile the code and execute it. Afterwards, if I try to view the resulting .ppm file in Gimp, it simply cannot open it. I guess I'm doing something wrong in my code. If someone could help me I would be glad.

// 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 Answers1

1

The newest version of your code works for me with 100 iterations and 1 thread.

enter image description here

Doing two threads fails, because the ppm file has 2 headers one from each thread.

If I delete one of the headers, the image loads but the colours are off and there's a glitch in the image.

enter image description here

parkydr
  • 7,596
  • 3
  • 32
  • 42
  • Ops, sorry, I had forgotten to add that part. I now edited and added to my original code the part for printing to file. I also tried using your code for printing but still now luck. –  Apr 23 '13 at 16:22
  • Did you change P6 to P3? That makes it ASCII according to gimp, or P2 for binary. – parkydr Apr 23 '13 at 17:39
  • Thanks for this info, but I'm using minimum of 10000 iterations and 10 threads. therefore, I need some other method, which will help me. –  Apr 23 '13 at 18:19
  • I also tried putting the header file in the main function, so it is not created each time a thread calls the function. This time I am able to open the file with any iteration and thread number, but the colours are off like in the picture that you have provided. –  Apr 23 '13 at 18:34
  • Though, if I edit my mandelbrot function, and use the threads in the first loop instead of the third one (in the iteration loop) like in my original example, my pictures work fine for any number of iterations and thread number less than or equal to 25. –  Apr 23 '13 at 18:47