Ошибка сегментации чтения элементов из массива C ++ - PullRequest
0 голосов
/ 15 ноября 2011

У меня есть следующие строки кода:

load()
{
    float* host;
    // init host done

    float** tran;

    printf("testing...\n");

    transpose(host, tran, 600);

    printf("testing. 3..\n");

    printf(" value =%d \n", tran[0][0]); // segmentation here

    printf("done...\n");
}

void transpose(float *input, float** output, int width)
{
    int size = 128*width*sizeof(float);

    // Allocate space on the GPU for input and output
    float* GPU_input = 0;   
    float** GPU_output;

    cudaMalloc(&GPU_input, size);
    cudaMalloc(&GPU_output, size);

    // Copy the input data to the GPU (host to device)
    cudaMemcpy(GPU_input, input, size, cudaMemcpyHostToDevice);

    dim3 threads(32, 32);
    dim3 grid(width/32+1, 128/32);

    printf("OK...\n");

    kernel_transpose<<< grid, threads >>>(GPU_input, GPU_output);

    printf("OK 2...\n");

    // Copy the input data to the GPU (host to device)
    cudaMemcpy(output, GPU_output, size, cudaMemcpyDeviceToHost);

    printf("OK 3...\n");

    cudaFree(GPU_input);
    cudaFree(GPU_output);

    printf("testing. 2..\n");
}

__global__ void kernel_transpose(float *array, float** output)
{
    int index_x = blockIdx.x*blockDim.x + threadIdx.x;
    int index_y = blockIdx.y*blockDim.y + threadIdx.y;

    output[index_x][index_y] = array[index_x+index_y];
}

Компиляция и запуск я получил:

testing...
OK...
OK 2...
OK 3...
testing. 2..
testing. 3..
line 84: 26819 Segmentation fault

Почему у меня "ошибка сегментации"? И, если возможно, как это исправить?

1 Ответ

3 голосов
/ 16 ноября 2011

host и tran должны быть выделены и инициализированы перед их использованием.Например, в C вы будете использовать malloc и free, проверяя возвращаемые значения в случае ошибок выделения:

// for strerror
#include <string.h>
...

int iobufsize(width) {
    return 128*width*sizeof(float);
}

float** alloc_matrix(...) {
    float **matrix, *pool;
    int i, eno=0;
    // allocate array of array pointers
    if ((matrix = (float**)malloc( ... ))) {
        /* Allocate array to hold data. This array will be divided up to
           create the arrays used in the matrix. Alternatively, each matrix array
           could be allocated separately.
         */
        if ((pool = (float*) malloc( ... ))) {
            for (i=0; i < ... ; i++) {
                // each item in matrix points to a subarray of the data array
                matrix[i] = pool + i * ...;
            }
        } else {
            /* free() shouldn't change errno, but this isn't guaranteed 
               for every implementation, so save errno to be safe.
             */
            eno = errno;
            free(matrix);
            errno = eno;
            matrix = NULL;
        }
    }
    return matrix;
}
void free_matrix(float **matrix, ...) {
    if (matrix) {
        free(*matrix);
        free(matrix);
    }
}

void load() {
    float* host;
    float** tran;
    int width = 600;
    int size = iobufsize(width);

    if ((host = (float*)malloc(size))) {
        if ((tran = alloc_matrix( ... ))) {
            // initialize 'host' buffer somehow
            ...

            printf("testing\n");

            transpose(host, tran, width);

            printf("testing 3\n");
            printf(" value =%d \n", tran[0][0]);
            printf("done\n");

            free_matrix(tran, ...);
            free(host);
        } else {
            /* Note: strerror isn't thread safe. If load() is run concurrently,
               make use of strerror_r instead.
             */
            fprintf(stderr, "Couldn't allocate output buffer: %s.\n", strerror(errno));
            free(host);
        }
    } else {
        fprintf(stderr, "Couldn't allocate input buffer: %s.\n", strerror(errno));
    }
}

В качестве улучшения вы можете связать матрицу (массивуказателей массива) в структуру вместе с размерами матрицы.Это шаг к созданию класса матрицы.

В C ++ вы будете использовать new[] и delete[], создавать классы для host и tran, которые будут членами другого класса, которыйуправляет взаимодействием.Это упрощает управление памятью (особенно всякий раз, когда new[] выдает bad_alloc), потому что вы можете применить шаблон RAII .

Существует довольно много других проблем с вашимкод.Когда вы выделяете (например, с cudaMalloc) или копируете (например, с cudaMemcpy) память, семантика (например, семантика указателя) не применяется к содержимому.Это имеет ряд последствий в вашем коде.С одной стороны, каждое распределение может дать вам только одномерный массив.Если вам нужны массивы более высокого размера, вы должны выделить массивы указателей для массивов меньшего размера, выделить массивы меньшего размера, а затем установить указатели в массиве более высокого измерения так, чтобы они указывали на массивы меньшего размера (как указано в alloc_matrix).Например, cudaMalloc(&GPU_output, size); создает одномерный массив float**, но не инициализирует содержимое.В результате у вас нет действительного массива указателей массива.

Кроме того, размер GPU_output неправильный;size - это общий размер данных, а не размер для многомерного массива.Эта ошибка возникает из-за обработки 1 и 2-х мерных массивов одинаковоони не.1-мерный массив - это непрерывная область памяти, где содержимое представляет собой последовательность объектов, которые имеют одинаковое расположение (т. Е. Элементы массива являются однородными).2-мерный массив - это массив указателей на массивы.В обоих случаях код обращается к массивам через указатели на первый элемент массива (например, host - указатель на первый элемент с плавающей запятой, trans - указатель на первый указатель на первый массив, который являетсяуказатель на первый элемент с плавающей точкой).alloc_matrix структурирует массивы так, что вы можете легко обрабатывать данные как имеющие 1 или 2 измерения, потому что сами массивы являются смежными (они взяты из непрерывной области памяти, на которую указывает pool).host[x][y] обрабатывает данные как имеющие 2 измерения.(*host)[x*n+y] (или host[0][x*n+y]), где n - размер одного массива данных, обрабатывает данные как имеющие 1 измерение.

То, что у вас есть:

float **GPU_output --> | float* | -> random memory location
                       | float* | -> random memory location
                          ....       (size / sizeof(float**) pointers total)
                       | float* | -> random memory location

что хочешь

float **GPU_output --> | float* | --> | float |
                                      | float |
                                         ...     
                                      | float |
                       | float* | --> | float |
                                      | float |
                                         ...     
                                      | float |  
                                  ...            
                       | float* | --> | float |
                                      | float |
                                         ...     
                                      | float |
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...