使用pthread打印二维数组

时间:2017-03-09 18:06:45

标签: c++ pthreads pthread-join

所以我有一个任务,说我创建了一个2-d数组[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 个答案:

答案 0 :(得分:0)

让我们看看threadf中的外部for循环,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.我的使用方式如下:list[i][j],请考虑写入list[14][11]的位置。在int list[5][12];定义的范围之外,将会出现Bad smurf。未定义的行为,所以在技术上没有人知道会发生什么。我们可以做一些相当不错的猜测。

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]

所以rowcolumn正在移动,但没有人关心。代码从不使用它们。但是threadc ......那个地方都在使用。实际上,它在循环退出条件中使用。这里可能会出现更多的不良情况。它还确定要创建和连接的线程数。可能无法创建某些线程。该程序可能会尝试加入比存在更多的线程。

无论如何,未定义的行为。我想我们都应该感到高兴的是,编译器没有生成下令进行战术核武攻击的代码。由于这是一个家庭作业问题,我不打算解释数学OP需要使他们的for循环正确地分配多个线程的工作,但是会建议他们将数组视为一维数组大小为5 * 12,并在单个for循环中进行1D-> 2D索引。

其他说明:

使用uintptr_t代替int代替i mainxthreadfuintptr_t保证会转换为void *

对循环计数器和数组索引器使用类似size_t的无符号变量。它们与uintptr_t很好地匹配,你几乎不需要负数组索引。

使用std::vector而不是指针和new作为线程列表。如果您必须使用new和指针,请记得在完成后删除列表。

看看您是否可以使用std::thread代替pthread

return添加到threadf

答案 1 :(得分:-1)

当创建的线程数为2时,不知何故thread_join会返回错误代码(在我的情况下为22)。如果在第二个循环中删除return语句,程序将打印最终输出。

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.html 22是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;
    }
    // ...