簡體   English   中英

Pthreads-將順序程序轉換為並行程序

[英]Pthreads - turning sequential programs into parallel

我正在用C ++模擬“ Conway的生活游戲”,其中2d矩陣表示電路板,0表示空單元,而1表示活單元。 我最初按順序編寫此文件,並嘗試使其與pthreads並行。 但是由於某種原因,該程序不再具有預期的性能。 盡管它經歷了兩個循環並似乎吸收了一些“計數++”,但並沒有吸收全部,因此該單元格的每一輪都被評估為只有一個或零個鄰居(即使那是並非如此)。 這導致在設定的時間段后的“結果”全為零,因為每個單元都死了而無法復制。 我已經為此工作了幾天,並做了很多不同的事情,但仍然無法解決。 這是我的代碼:

#include <iostream>
#include <vector>
#include <pthread.h>
#include <cstdlib>
#include <functional>
using namespace std;
pthread_mutex_t mymutex;
int lifetime, numthreads = 5;
vector<vector<int> > board,result,pending;

void *loader(void *tid){
    long thid = long(tid);
    int n = board.size();
    result = board;
    int count = 0;
        for(long i = 0; i < n; i ++){
            if(i % numthreads != thid)
                continue;
            for(long j = 0; j < n ; j++){
                if(i % numthreads != thid)
                    continue;
                if(i+1 < n){
                    if(result[i+1][j] == 1) //checking each of the neighbor
                        count++
                        ;
                    if(j+1 < n){
                        if(result[i+1][j+1] == 1)
                            count++;
                    }
                    if(j-1 >= 0){
                        if(result[i+1][j-1] == 1)
                            count++;
                    }
                }
                if(j-1 >= 0){
                    if(result[i][j-1] == 1)
                        count++;
                }
                if(j+1 < n){
                    if(result[i][j+1] == 1)
                        count++;
                }
                if(i-1 >= 0){
                    if(result[i-1][j] == 1)
                        count++;
                    if(j+1 < n){
                        if(result[i-1][j+1] == 1)
                            count++;
                    }
                    if(j-1 >= 0){
                        if(result[i-1][j-1] == 1)
                            count++;
                    }
                }
                //determining next state
                if(count <= 1 || count >= 4){ //this utilizes the three main rules of game
                    pthread_mutex_lock(&mymutex);
                    pending[i][j] = 0;
                    pthread_mutex_unlock(&mymutex);
                }else if(count == 3){
                    pthread_mutex_lock(&mymutex);
                    pending[i][j] = 1;
                    pthread_mutex_unlock(&mymutex);
                }else{
                    pthread_mutex_lock(&mymutex);
                    pending[i][j] = result[i][j];
                    pthread_mutex_unlock(&mymutex);
                }
                count = 0;
                pthread_mutex_lock(&mymutex);
                result = pending;
                pthread_mutex_unlock(&mymutex);
            }
        }
        pthread_exit(NULL);
        return NULL;
}

int main(){
    //setting up input
    int n;
    cin >> n;
    board.resize(n);
    result.resize(n);
    pending.resize(n);
    for(int i = 0; i < board.size(); i++){
        board[i].resize(n);
        result[i].resize(n);
        pending[i].resize(n);
    }
    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            cin >> board[i][j];
        }
    }

    cin >> lifetime;

    //making threads, enacting fn
    pthread_t threads[numthreads];
    void *status[numthreads];
    pthread_mutex_init(&mymutex,NULL);
    int rc;
    for(int i = 0; i < lifetime; i++){
        for(int t = 0; t < numthreads; t++){
            rc = pthread_create(&threads[t],NULL,loader,(void *)t);
            if(rc)
                exit(-1);
        }
        for(int t = 0; t < numthreads; t++){
            rc = pthread_join(threads[t],&status[t]);
            if(rc)
                exit(-1);
        }
    }

    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            cout << result[i][j] << " ";
        }
        cout << endl;
    }
}

算是私有的,對吧,因為它是在線程初始化之后創建的? 那是我唯一能想到的。 也許我的循環執行不正確,但這是我編寫的第一個pthreads程序,因此我不確定還是嵌套嵌套循環的最佳方法。

我可以立即看到三個正確性問題。

首先,每個線程都將result = board為無鎖定狀態,並且您甚至不想執行每個循環。 只需讓主線程執行一次操作-后續迭代就將result用作其輸入。

其次,這些嵌套循環:

for(long i = 0; i < n; i ++){
    if(i % numthreads != thid)
        continue;
    for(long j = 0; j < n ; j++){
        if(i % numthreads != thid)
            continue;
        /* ... */

表示列行都必須匹配線程ID-這意味着將跳過大多數單元格。 例如,如果numthreads為3,則線程0將訪問[0][0][0][3] ,...,線程1將訪問[1][1] [1][4] ,...,但是沒有線程會訪問[0][1] (因為該行匹配線程0,而該列匹配線程1)。

您可以通過僅在線程之間划分行並讓一個線程處理整個行來解決此問題:

for(long i = 0; i < n; i ++){
    if(i % numthreads != thid)
        continue;
    for(long j = 0; j < n ; j++){
        /* ... */

第三, 每個線程在處理完每個單元格之后都會更新result -這意味着某些單元格是根據其他單元格的部分結果來計算其結果的,而這甚至沒有確定的順序發生,因此結果將不穩定。

您可以通過刪除loader()函數中更新result的代碼,並將其放入main()lifetime循環中來解決此問題,因此在游戲的每個步驟中都只會發生一次。

還有一個性能問題-您正在游戲的每個步驟中啟動和停止大量線程。 這根本不能很好地執行-啟動和停止線程是一項重量級的操作。 一旦工作,就可以通過讓每個線程執行lifetime循環並始終保持運行來解決此問題。 您可以使用pthread_barrier_wait()在每一步進行同步。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM