使用没有互斥锁的线程增加全局变量会奇怪地返回正确的值

时间:2018-03-14 13:23:59

标签: c multithreading pthreads global mutex

我们被要求创建4个线程,每个增量(SPIN / 4次)全局变量compteur的值应该注意到每个线程在另一个线程完成之前访问/更改全局变量迭代(为SPIN给出一个非常大的数字的原因),例如第一个线程1访问compteur,并且当它增加另一个线程访问compteur并看到{ {1}}最后总结说我们必须使用MUTEX。

问题在于程序总是给我与SPIN相同的价值。

你能解释一下为什么吗?

compteur = 0

3 个答案:

答案 0 :(得分:1)

当你在循环中调用pthread_join时,主线程处于空闲状态并等待另一个线程退出。因此,您将获得如下工作流程:

Run thread 0
Wait for thread 0
Thread 0 exited
Run thread 1
Wait for thread 1
Thread 1 exited
...

没有线程同时运行。

您应该将正在运行的线程循环和等待的线程循环分开。

for(i= 0; i< 4; i++) {
  statut = pthread_create(&thread_id[i], NULL, routine_thread, NULL);           
  if(statut != 0) {
    fprintf(stderr, "error creating thread\n");
    exit(EXIT_FAILURE);                 
  }
}
for(i= 0; i< 4; i++) {
  statut = pthread_join(thread_id[i], &resultat_thread);
  if(statut != 0) {
    fprintf(stderr, "error joining the thread\n");
    exit(EXIT_FAILURE);
  }
}

答案 1 :(得分:0)

您已经序列化了您正在创建的主题。循环内的pthread_join()调用在创建下一个线程之前等待线程完成。 因此,您可以随时修改compteur一个活动线程(主线程除外)。所以你没有期待观察到data race

从循环中删除pthread_join个调用。并制作另一个循环来等待线程:

      for(i= 0; i< 4; i++) {
        statut = pthread_join(thread_id[i], NULL);

        if(statut != 0) {
            fprintf(stderr, "error joining the thread\n");
            exit(EXIT_FAILURE);
        }
      }

您的线程功能不会返回任何值。因此,您可以在NULL来电中使用&resultat_thread代替pthread_join

答案 2 :(得分:0)

   for(i= 0; i< 4; i++) {

            statut = pthread_create(&thread_id[i], NULL, routine_thread, NULL);         

                     if(statut != 0){
                        fprintf(stderr, "error creating thread\n");
                        exit(EXIT_FAILURE);                 
                     }

            statut = pthread_join(thread_id[i], &resultat_thread);

                    if(statut != 0){
                       fprintf(stderr, "error joining the thread\n");
                       exit(EXIT_FAILURE);
                    }
  }

此代码创建一个线程并等待线程完成执行。因此,线程将访问全局变量compteur,这就是每次获得相同值的原因。

要实现所有线程增量的目标(SPIN / 4次)全局变量compteur的值,您应该首先创建所有4个线程pthread_create(),然后调用pthread_join()等待它。