2017-03-09 134 views
1

所以我有一个任务,说我已经创建了一个二维数组[5] [12],随机值在1-99之间。然后使用pthreads,我必须为数组中的每个元素加1或减1,然后打印结果并将进程分成2,3或4个线程。线程的数量取决于用户在命令行上输入的内容。我有编译和运行的代码。但是,我希望的输出仅在输入数字3时打印。你能告诉我我的代码出错了吗?我在开始时无法理解pthread。使用pthread打印二维数组

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

这是一个家庭作业? – hmatar

+0

是的。这是不允许的吗? –

+0

这是允许的,到目前为止,它看起来像你展示你的工作。尽管推荐一些更改:“我的期望输出”显示此。同时显示你正在得到的东西。建议:开始时不要使用随机数字,这样您就可以一遍又一遍地测试相同的数字,直到您将线程整理出来。更容易找出改进或错误。 – user4581301

回答

-1

不知怎的thread_join(在我的情况22)返回一个错误代码时创建的线程数是2。如果您删除在第二循环中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的返回值,我建议您在thredf的末尾添加一个成功的终止函数(pthread_exit(NULL);)。此外,为了避免@ 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; 
    } 
    // ... 
+0

类别。这通过侥幸。 0x03意味着没有这样的线程,所以你只是掩盖另一个错误。你想知道的是为什么没有第二个线程? – user4581301

+0

@user为了您的解决方案,您不必关心thread_join返回的内容。因为有一些条件返回错误可能是有用的:线程死锁或EINVAL。如果你仔细观察POSIX教程,大部分的例子都不会看这个函数返回什么。父线程调用此函数的最基本工作是阻塞,直到其所有子线程终止。我多年来一直在编写多线程程序,而且我没有关心这个函数返回什么。重要的是它的行为。 – hmatar

+0

不是我的解决方案,老兄。真正的问题是'threadf'中的缓冲区溢出,你的答案只是隐藏了这个。 – user4581301

0

让我们看看在外部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.我正在像这样使用: list[i][j],所以请考虑写入list[14][11]的地方。那么在int list[5][12];定义的界限之外就会发生不良的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所要求的数学运算,以使它们正确分配跨多个线程的工作,但会建议他们将数组视为尺寸为5 * 12的一维数组并在一个for循环中自己完成1D-> 2D索引。

其他说明:在main

使用uintptr_t代替intithreadfxuintptr_t保证转换为void *

使用像size_t这样的无符号变量作为循环计数器和数组索引器。他们与uintptr_t很好地玩,你几乎从不想要一个负数组索引。

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

看看您是否可以使用std::thread而不是pthread s。

添加returnthreadf