此代码计算数组中所有整数的总和,将工作平均分配到多个线程之间。但是,每隔一段时间,线程号以及线程的localsum就会混乱。我假设这是因为void * param和globalindex被多个线程同时访问。即使我在此代码中互锁了每个全局变量,也没有发生这样的事实。 我该如何解决?
#include<string>
#include<iostream>
#include<fstream>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
using namespace std;
int y =0;
int sum=0;
int array[1000000];
int x=0;
int leftoverHandle = 0;
int globalindex = 0;
int eachThreadHandles =0;
void* add(void* param){
pthread_mutex_lock(&mutex);
int localindexup = globalindex + eachThreadHandles;
int localindexdown = globalindex;
int localsum=0;
long localparam = (long)param;
if(y != leftoverHandle ){
localindexup++;
y++;
}
pthread_mutex_unlock(&mutex);
while(localindexdown<localindexup){
pthread_mutex_lock(&mutex);
sum = sum+array[localindexdown];
localsum = localsum+array[localindexdown];
localindexdown++;
pthread_mutex_unlock(&mutex);
}
pthread_mutex_lock(&mutex);
globalindex = localindexdown;
printf("Thread %ld", localparam);
printf(": %d\n", localsum);
pthread_mutex_unlock(&mutex);
}
int main(int argc, char ** argv){
if(argc != 3){
cout<<"Incorrect number of argument";
exit(1);
}
string line;
string f = argv[1];
const char *filename = f.c_str();
int maxthreads = atoi(argv[2]);
FILE* inFile = fopen(filename,"r");
int i=0;
if(inFile == NULL){
cout<<"fopen failed"<<endl;
}
fscanf(inFile, "%d",&i);
while(!feof(inFile)){
array[x]=i;
x +=1;
fscanf(inFile,"%d",&i);
}
fclose(inFile);
pthread_t id[maxthreads];
leftoverHandle = x%maxthreads;
eachThreadHandles = (x - leftoverHandle)/maxthreads;
for(long i=0; i< maxthreads;i++){
long status = pthread_create(&id[i], NULL, add, (void*) i);
if(status){
printf("Error creating thread! \n");
exit(0);
}
}
for(long i=0; i<maxthreads;i++){
pthread_join(id[i], NULL);
}
cout<<"Sum="<<sum<<endl;
return 0;
}
答案 0 :(得分:1)
问题在于,每个线程都初始化globalindex
和localindexup
之后,即在第一个关键部分中,您没有立即更新localindexdown
。
您的代码中包含三个关键部分。
假设thread0
运行第一个关键部分,然后thread1
在thread0
释放第一个关键部分的锁定之后立即抢占thread0
。但是由于您是在第三关键部分(而非第一关键部分)中将globalindex
设置为localindexdown
,因此thread1
仍会看到globalindex=0
,就像thread0
一样,因此它会重新计算与thread0
相同的总和。您应将globalindex = localindexdown;
放入第一关键部分。
实际上,根本不需要第三关键部分:
pthread_mutex_lock(&mutex);
int localindexup = globalindex + eachThreadHandles;
int localindexdown = globalindex;
int localsum=0;
long localparam = (long)param;
if(y != leftoverHandle ){
localindexup++;
y++;
}
globalindex = localindexdown; //<--- MOVED HERE
pthread_mutex_unlock(&mutex);
忘记我对循环的评论,我犯了一个错误:while(localindexdown<localindexup)
可以被安全地抢占,因为变量没有在线程之间共享。您可以通过减少互斥区域仅包含共享数据来稍微提高性能:
while(localindexdown<localindexup)
{
pthread_mutex_lock(&mutex);
sum = sum+array[localindexdown];
pthread_mutex_unlock(&mutex); //<--- MOVED HERE
localsum = localsum+array[localindexdown];
localindexdown++;
}