Pthreads - 将顺序程序转换为并行程序

时间:2017-02-28 01:27:35

标签: c++ multithreading parallel-processing pthreads mutex

我用C ++模拟“康威的生命游戏”,其中2d矩阵表示棋盘,0表示空单元格而1表示活细胞。我最初是按顺序编写的,并尝试使其与pthreads并行。但出于某种原因,该程序不再按预期运行。虽然它经历了两个循环并且似乎接收了一些“count ++”,但它并没有拾取所有这些,因此每个圆形单元被评估为只有一个或零个邻居(即使这是不是这样)。这导致在设定的时间段之后的“结果”全为零,因为每个单元都死亡而不能再现。我一直在研究这个问题并改变了不同的事情,但仍然无法弄明白。这是我的代码:

#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程序,所以我不确定制作嵌套for循环的最佳方法。

1 个答案:

答案 0 :(得分:0)

我可以立即看到三个正确性问题。

首先,每个线程都设置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 - 这意味着某些单元格正在根据其他单元格的部分结果计算结果,这甚至不会以确定的顺序发生,因此结果将不稳定。

您可以通过移除result函数中更新loader()并将其放入lifetime循环main()中的代码来解决此问题,因此只需执行一次游戏的每一步。

还有一个性能问题 - 你在游戏的每一步都开始并停止一堆线程。这根本不会表现得很好 - 启动和停止线程是一项重量级操作。一旦你有了它,你可以通过让每个线程执行lifetime循环并保持一直运行来解决这个问题。您可以使用pthread_barrier_wait()在每个步骤进行同步。