Использование pthread для печати 2-го массива

Итак, у меня есть задание, которое говорит, что я создал двумерный массив [5][12] со случайными значениями от 1 до 99. Затем, используя pthreads, я должен либо добавить 1, либо вычесть 1 для каждого элемента в массиве, а затем распечатать результаты и разделить процесс на 2, 3 или 4 потока. Количество потоков зависит от того, что пользователь вводит в командной строке. У меня есть код, который компилируется и запускается. Тем не менее, мой желаемый вывод печатается только при вводе номера 3. Не могли бы вы, ребята, сказать мне, где я ошибся в своем коде? У меня проблемы с пониманием pthreads для начала.

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#include <pthread.h>
#include <iostream>

using namespace std;
int list[5][12];
int rows = 5;
int cols = 12;
int threadc;

void *threadf(void *arg)
{
    int x = (int) arg;
    for(int i = (x*60)/threadc; i < ((x+1) * 60)/threadc; i++)
    {
        for(int j = 0; j < 12; j++)
        {
            if (list[i][j] % 2 == 0)
                list[i][j] += 1;
            else
                list[i][j] -= 1;
        }
    }
}

void cArray()
{
    srand(time(NULL));
    for(int i = 0; i < 5; i++)
    {
        for(int j = 0; j < 12; j++)
        {
            list[i][j] = rand() % 99 + 1;
        }
    }

}

void pArray(int list[][12], int rows, int cols)
{
    cout << "\n";
    for(int i = 0; i < rows; i++)
    {
        for(int j = 0; j < cols; j++)
        {
            cout << list[i][j] << " ";
        }
        cout << "\n";
    }
 }

int main(int argc, char *argv[])
{
    if(argc != 2) exit(0);
    threadc = atoi(argv[1]);
    assert(threadc >= 2 && threadc <=4);
    pthread_t *thread;
    thread = new pthread_t [threadc];
    if(thread == NULL)
        exit(0);
    cArray();
    cout << "2-d Array: ";
    pArray(list, rows, cols);
    int t;
    for(int i = 0; i < threadc; i++)
    {
        t = pthread_create(&thread[i], NULL, threadf, (void *)i);
        if (t != 0)
            return 1;
    }
    for(int i = 0; i < threadc; i++)
    {
        t = pthread_join(thread[i], NULL);
        if(t != 0)
            return 1;
    }  
    cout << "Modified 2-d Array: ";
    pArray(list, rows, cols);
    return 0;
}

2 ответа

Решение

Как -то thread_join возвращает код ошибки (22 в моем случае), когда число созданных потоков равно 2. Если вы удалите оператор возврата во втором цикле, ваша программа напечатает окончательный результат.

for(int i = 0; i < threadc; i++)
{
    t = pthread_join(thread[i], NULL);
    if (t != 0) 
        return 1; // <- your program works if you comment out this.


}

Согласно этой ссылке: http://minirighi.sourceforge.net/html/errno_8h.html22 - это EINVAL, что означает "поток не присоединяется".

Поскольку вы заботитесь о возвращаемом значении pthread_join, я бы посоветовал добавить функцию успешного завершения (pthread_exit(NULL);в конце вашего thredf, Кроме того, чтобы избежать переполнения буфера, как указано @user4581301, вы можете передать указатель на данные.

Так thredf было бы как

void *threadf(void *arg)
{
    cout << endl;
    int x = *((int*)arg); // <- NOTICE HERE!
    for(int i = (x*60)/threadc; i < ((x+1) * 60)/threadc; i++)
      //...
    }
    pthread_exit(NULL); // <- NOTICE HERE!
}

И главное:

int main(int argc, char *argv[])
{
    if(argc != 2) exit(0);
    threadc = atoi(argv[1]);
    assert(threadc >= 2 && threadc <=4);
    pthread_t *thread;
    thread = new pthread_t [threadc];
    int *data = new int[threadc]; // <- NOTICE HERE!

    if(thread == NULL)
        exit(0);
    cArray();
    cout << "2-d Array: ";
    pArray(list, rows, cols);
    int t;
    for(int i = 0; i < threadc; i++)
    {
        data[i] = i;
        //                                                NOTICE HERE!
        t = pthread_create(&thread[i], NULL, threadf, (void *)(&data[i])); 
        if (t != 0)
            return 1;
    }
    // ...

Давайте посмотрим на внешний цикл for в threadf для x = 0 и threadc = 4

    for(int i = (0*60)/4; i < ((0+1) * 60)/4; i++)
    for(int i = 0; i < (1 * 60)/4; i++)
    for(int i = 0; i < 60/4; i++)
    for(int i = 0; i < 15; i++)

i колеблется от 0 до 14. i используется следующим образом: list[i][j]так что посмотрим где пишет в list[14][11] пойдет. Хорошо вне границ, определенных int list[5][12]; Будет плохой смарф. Неопределенное поведение, поэтому технически никто не знает, что произойдет. Мы можем сделать довольно хорошие предположения, хотя.

int list[5][12];
int rows = 5; // probably overwritten by write to list[6][0]
int cols = 12; // probably overwritten by write to list[6][1]
int threadc; // probably overwritten by write to list[6][3]

Так row а также column движутся, но никому нет дела. Код никогда не использует их. Но threadc... Это используется повсеместно. Фактически он используется в состоянии выхода из цикла. Больше зла может произойти здесь. Он также определяет количество потоков, которые будут созданы и объединены. Некоторые темы не могут быть созданы. Программа может попытаться присоединиться к большему количеству потоков, чем существует.

Во всяком случае, неопределенное поведение. Я полагаю, что мы все должны быть рады, что компилятор не генерировал код, который заказывал тактический ядерный удар. Так как это домашнее задание, я не собираюсь разгадывать математику. for Цикл правильно распределить работу между несколькими потоками, но предложит рассмотреть обработку массива как массива 1D размером 5*12 и выполнение индексации 1D->2D в одном for петля.

Другие заметки:

использование uintptr_t вместо int за i в main а также x в threadf, uintptr_t гарантированно конвертировать в void *

Используйте переменную без знака, например size_t для счетчиков цикла и индексаторов массива. Они хорошо играют с uintptr_t и вы почти никогда не хотите отрицательный индекс массива.

Использовать std::vector вместо указателя и new для списка тем. Если вы должны использовать new и указатель, не забудьте удалить список, когда вы закончите с ним.

Посмотрите, можете ли вы использовать std::thread вместо pthreads.

Добавить return в threadf,

Другие вопросы по тегам