Ошибка сегментации с memcpy в C в параллельном алгоритме Мандельброта: как использовать указатели в структуре? - PullRequest
0 голосов
/ 27 апреля 2018

Цель состоит в том, чтобы написать распараллеливание из последовательного алгоритма Мандельброта. У меня проблемы с типами данных и указателями.

Вот так выглядит мой main.c:

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);
}

Первое, с чем я борюсь, это линия unsigned char (*image)[x_resolution][3]; Насколько я понимаю, я создаю указатель с *image. Я также знаю использование скобок при работе с массивами. Но я не очень понимаю, какой тип данных я получаю с этим.

Тогда мой параллельный алгоритм начинается так:

#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;
};

Мне нужна эта структура, потому что мне нужно передать аргументы в pthreads_create, и эта функция может получить только один аргумент для ввода. Я исследовал, как вы можете работать с указателем внутри структуры, и сделал это, как предложено здесь: Хранение и доступ к 2D-массиву в структуре

У меня также есть следующие функции в моем коде:

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;
}

И вот моя главная проблема: я получаю ошибку сегментации в memcpy(&args->img[i][j], "\0\0\0", 3);. Я думаю, что я делаю что-то действительно не так с указателями, но я не могу понять, что я должен делать.

1 Ответ

0 голосов
/ 27 апреля 2018

Ваша проблема в том, что указатель изображения указывает на один большой трехмерный массив. Это целая куча ценностей в памяти. Я попытался нарисовать картинку для представления трехмерного массива ниже.

Но затем вы пытаетесь использовать его как одномерный массив указателей на одномерные массивы. Каким бы способом вы не нарезали его, это, возможно, не сработает, поскольку в вашем массиве нет указателей.

Вы должны изменить тип:

unsigned char** img;

, чтобы оно совпадало с main:

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

А затем заменить это:

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

только с:

args[i].img = img;

Я вижу, что вы использовали memcpy, потому что компилятор жаловался, что вы пытаетесь назначить указатель на другой тип указателя. Компилятор пожаловался по причине.

...