[英]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.