2

The goal is to write a parallelization out of a sequential mandelbrot algorithm. I'm having some problems with my the data types and pointers.

This is how my main.c looks like:

int main(int argc, char **argv)
{
    /****
    Here are initializations and some for my question irrelevant code...
    *****/

    unsigned char (*image)[x_resolution][3];
    image = malloc(x_resolution * y_resolution * sizeof(char[3]));

    // compute mandelbrot   
    mandelbrot_draw(x_resolution, y_resolution, max_iter, view_x0, view_x1,
    view_y0, view_y1, x_stepsize, y_stepsize, palette_shift, image, 
    num_threads);

    free(image);
}

The first thing that I'm struggling with, is the line unsigned char (*image)[x_resolution][3]; The way I understand it, is that I'm creating a pointer with *image. I also know the use of brackets from dealing with arrays. But I do not really understand what data type I get with this.

Then my parallel algorithm starts like this:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <complex.h>
#include <pthread.h>
#include "mandelbrot.h"

struct pthread_args_struct
{
    int x_resolution;
    int y_resolution_lower_boundary;
    int y_resolution_upper_boundary;
    int max_iter;
    double view_x0;
    double view_y1;
    double x_stepsize;
    double y_stepsize;
    int palette_shift;

    unsigned char** img;
};

I need this struct because I need to pass arguments to pthreads_create, and this function can only get one argument for input. I researched how you can deal with a pointer inside a struct and did it like suggested here: Storing and Accessing a 2D Array in a Struct

I also have the following to functions in my code:

void mandelbrot_draw(int x_resolution, int y_resolution, int max_iter,
                double view_x0, double view_x1, double view_y0, double 
                view_y1, double x_stepsize, double y_stepsize,
                int palette_shift, unsigned char (*img)[x_resolution][3],
                int num_threads) {

    //I split the image into rows 
    //  and let each thread calculate the pixels for one row
    int y_resolution_thread[num_threads+1]; 
    for (int t = 0; t < num_threads; t++)
    {       
        y_resolution_thread[t] = t*(y_resolution/num_threads);
        y_resolution_thread[num_threads] = y_resolution;
    }

    //allocate pthreads space and space for struct
    pthread_t *threads = (pthread_t*) malloc (num_threads*sizeof(pthread_t));
    struct pthread_args_struct* args = (struct pthread_args_struct*) malloc 
    (num_threads*sizeof(struct pthread_args_struct));

    //create threads, start mandelbrot_draw_row in parallel
    for(int i = 0; i < num_threads; ++i) {
        args[i].y_resolution_lower_boundary = y_resolution_thread[i];
        args[i].y_resolution_upper_boundary = y_resolution_thread[i+1];         
        args[i].x_resolution = x_resolution;
        args[i].max_iter = max_iter;
        args[i].view_x0 = view_x0;
        args[i].view_y1 = view_y1;
        args[i].x_stepsize = x_stepsize;
        args[i].y_stepsize = y_stepsize;
        args[i].palette_shift = palette_shift;

        memcpy(&args[i].img, img, sizeof(img));

        //create thread and pass arguments
        pthread_create (&threads[i] , NULL, mandelbrot_draw_row, args+i);
    }

    //wait for finish and join
    for (int i = 0; i < num_threads; ++i){
        pthread_join(threads[i], (void*)&img);
    }

    free(threads); free(args);
    return((void*) &img);
}

void* mandelbrot_draw_row (void* args){

    struct pthread_args_struct* arg = (struct pthread_args_struct*) args;
    arg->img = malloc(sizeof(arg->img));

    int k;

    for (int i = arg->y_resolution_lower_boundary; i < arg-> 
    y_resolution_upper_boundary; i++)
    {
        for (int j = 0; j < arg->x_resolution; j++)
        {
            k = 0;
            //do some calculations here

            if (k == arg->max_iter)
            {   
                memcpy(&args->img[i][j], "\0\0\0", 3); <- here I get a 
                                                         segmentation fault
            }
            else
            {
                int index = (k + arg->palette_shift)
                        % (sizeof(colors) / sizeof(colors[0])); 
                memcpy(&args->img[i][j], colors[index], 3);
            }
        }
    }
    return(void*) &arg->img;
}

And here comes my main problem: I get a segmentation fault in memcpy(&args->img[i][j], "\0\0\0", 3);. I think I'm doing something really wrong here with the pointers, but I cannot really understand what I'm supposed to do.

WedaPashi
  • 3,561
  • 26
  • 42
Laura
  • 21
  • 1
  • Thanks much, this already helped a lot. I went for @immibis solution because I cannot hand in a modified main.c for my assignment. I changed the type to `unsigned char (*image)[][3]` because it is not possible to use the x_resolution element in the definition of the struct. If I use `unsigned char (*image)[x_resolution][3]` my compiler says "x_resolution undeclared here". So I'm trying to do it like suggested here: https://stackoverflow.com/questions/32400028/can-one-element-in-struct-access-another-element-of-itself-in-c?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa – Laura Apr 27 '18 at 16:21
  • 1
    I tried my program with a fixed array size in the struct definition (`unsigned char (*image)[1000][3]`) and then everything works super well. But if I try to do it with a variable array size I'm stuck. I get an error saying I'm using an array with unspecified bounds in memcpy, which is actually true :D I just don't where and how to allocate the memory or specify how long my array finally is. If someone would have an answer for that, I would be more than happy! – Laura Apr 27 '18 at 16:31

1 Answers1

0

Your problem is that your image-pointer is pointing to a single, big 3D array. It's a whole bunch of values right next to each other in memory. I've tried to draw a picture to represent a 3D array below.

But then you're trying to use it like a 1D array of pointers to 1D arrays. Whichever way you slice it, this won't possibly work because your array doesn't have pointers in it to begin with.

You should change the type:

unsigned char** img;

so that it matches the one in main:

unsigned char (*image)[x_resolution][3];

And then replace this:

memcpy(&args[i].img, img, sizeof(img));

with just:

args[i].img = img;

I see you were using memcpy because the compiler complained you were trying to assign a pointer to a different type of pointer. The compiler complained for a reason.

user253751
  • 57,427
  • 7
  • 48
  • 90