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

Incrementing the global variable using threads without a mutex strangely returns correct value

我们被要求创建 4 个线程,每个线程递增(SPIN/4 倍)全局变量 compteur 的值,据说每个线程都是 accessing/changing 全局变量在另一个完成迭代之前(这就是为什么 SPIN 被赋予一个非常大的数字),例如线程号 1 首先访问 compteur 并且当它递增另一个线程访问 compteur 并看到 compteur = 0仍然,最后得出结论,我们必须使用 MUTEX。

问题是程序总是在不应该的情况下给我与 SPIN 相同的值。

你能解释一下为什么吗?

#define SPIN 40000000

int compteur = 0;

void *routine_thread(void *arg) {
  int i;
  printf("accessing thread ... \n");

  for (i = 0; i < SPIN / 4; ++i) {
    compteur++;
  }
  printf("quitting thread ... \n");
  pthread_exit(NULL);
}

int main(int argc, char *argv[]) {
  pthread_t thread_id[4];
  void *resultat_thread;
  int statut;
  int i;

  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);
    }
  }

  printf("compteur value is : %d\n", compteur);

  if (resultat_thread == NULL)
    return EXIT_FAILURE;
  else
    return EXIT_SUCCESS;
}

当你在循环中调用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);
  }
}

您已经序列化了正在创建的线程。 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);
        }
      }

您的线程函数没有 return 任何值。因此,您可以在 pthread_join 调用中使用 NULL 而不是 &resultat_thread

   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);
                    }
  }

此代码创建一个线程并等待线程完成它 execution.so 全局变量 compteur 将被线程访问一次,这就是为什么你每次都获得相同的值。

要实现objective所有线程的增量(SPIN/4倍)全局变量compteur的值同时你应该先创建所有4个线程pthread_create() 然后调用pthread_join()等待