多个线程更新同一变量时出现意外输出

时间:2017-12-05 11:11:58

标签: c multithreading pthreads

#include<stdio.h>
#include<pthread.h>
#define NUM_THREAD (5)

int sum=0;
void* runner(void * param);

int main(int argc,char **argv){

    pthread_t tid[NUM_THREAD];
    pthread_attr_t attr;
    pthread_attr_init(&attr);

    for(i=0;i<NUM_THREAD;i++){
    pthread_create(&tid[i],&attr,runner,NULL);
    }
    for(i=0;i<NUM_THREAD;i++){
    pthread_join(tid[i],NULL);
            }
    printf("After threading %d",sum);
    return 0;
}


void * runner(void *param){
    for(int j = 0;j<10;j++)  sum+=j;    
    pthread_exit(0);

}

输出:225

在下面的代码中,输出是225.但是正确的应该是45

我知道线程共享全局变量!所以这个功能应该正确输出。但是在内部添加sum = 0只能得到正确的输出。发生什么事在这里我不明白!

void * runner(void *param){
sum=0;   // MY DOUBT 
for(int j = 0;j<10;j++)  sum+=j;    
    pthread_exit(0);

}

输出:45

3 个答案:

答案 0 :(得分:4)

您有data race因为所有线程都访问/修改sum而没有任何同步。所以45和225都是“错误的”。您可能会在不同的运行中看到不同的值。您需要synchronize访问sum

要注意的另一件事是你没有初始化attr,而是传递给pthread_create。您需要使用pthread_attr_init初始化它。

答案 1 :(得分:3)

你正在处理的是竞争条件。对于每个系统,您将获得不同的输出。此代码的行为不是确定性的。 因为,当您在循环中创建每个线程时,将以无法知道的顺序调用迭代10次的runner函数。

因此,期待45245或其他任何事情是错误的。

当多个线程可以同时修改公共/共享数据时,竞争条件是一种不受欢迎的情况,因为它们可以访问它。 可以在系统与系统之间表现不同的调度程序可以在任何时间点在这5个线程之间切换。要获得确定性行为,需要通过Mutex或Semaphore等同步技术来解决这个问题。

Mutex是我最喜欢的。不是为你编写完整的代码,因为它没有必要的问题,我很懒。

执行相同操作的粗略步骤是:

创建线程的地方

  • 在创建线程之前初始化Mutex
  • 创建线程(0到n)
  • 完成后销毁Mutex
  • pthread_join

在线程处理程序中,在您的情况下runner函数,

  • 锁定互斥锁
  • 做点什么
  • 解锁Mutex(别忘了!)

因此,您的main应包含pthread_mutex_init,如果确实返回NULL,则可以继续。

runner函数中,pthread_mutex_lock(&lock);应该是它做的第一件小事,然后是你的代码,然后在它返回之前最后pthread_mutex_unlock(&lock);

您创建的互斥锁可以被pthread_mutex_destroy销毁。

很有趣!

答案 2 :(得分:1)

您正在从5个线程修改一个全局对象。一个线程将sum的值增加45,所以当你将它乘以5时,你就有225。

这里的另一个问题是你修改了每个线程中的一个变量,这可能会导致比赛导致的一些混乱。