我用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循环的最佳方法。
答案 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()
在每个步骤进行同步。