尽管互斥锁,线程中的竞争条件

时间:2019-10-12 02:00:19

标签: c++ multithreading pthreads race-condition

此代码计算数组中所有整数的总和,将工作平均分配到多个线程之间。但是,每隔一段时间,线程号以及线程的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;
}

1 个答案:

答案 0 :(得分:1)

问题在于,每个线程都初始化globalindexlocalindexup之后,即在第一个关键部分中,您没有立即更新localindexdown
您的代码中包含三个关键部分。
假设thread0运行第一个关键部分,然后thread1thread0释放第一个关键部分的锁定之后立即抢占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++;
    }