2017-03-09 135 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