【问题标题】:How to fix my Pthreads code about Mandelbrot set?如何修复关于 Mandelbrot 集的 Pthreads 代码?
【发布时间】:2013-04-23 11:48:11
【问题描述】:

我有以下关于计算和创建 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 个线程(100 次迭代)

标签: c image pthreads set mandelbrot


【解决方案1】:

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

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

如果我删除其中一个标题,图像会加载,但颜色会关闭,并且图像中存在故障。

【讨论】:

  • 操作,抱歉,我忘记添加那部分了。我现在编辑并将打印到文件的部分添加到我的原始代码中。我也尝试使用您的代码进行打印,但现在仍然很幸运。
  • 你把P6改成P3了吗?这使得它根据 gimp 为 ASCII,或 P2 为二进制。
  • 感谢您提供此信息,但我至少使用了 10000 次迭代和 10 个线程。因此,我需要一些其他方法来帮助我。
  • 我也试过把头文件放在main函数中,所以每次线程调用函数时都不会创建。这次我可以使用任何迭代和线程号打开文件,但颜色与您提供的图片中的颜色一样。
  • 不过,如果我编辑我的 mandelbrot 函数,并在第一个循环中使用线程而不是像在我的原始示例中那样使用第三个循环(在迭代循环中),我的图片适用于任意数量的迭代次数和线程数小于或等于 25。
猜你喜欢
  • 2013-04-13
  • 2011-08-08
  • 2015-10-02
  • 1970-01-01
  • 2013-04-14
  • 1970-01-01
  • 2020-02-05
  • 2019-09-13
  • 2017-05-12
相关资源
最近更新 更多