为什么这段代码在没有互斥量的情况下也能工作?

Why does this code work without a mutex?

我正在尝试了解锁在多线程中的工作原理。当我在没有锁定的情况下执行以下代码时,它工作正常,即使变量 sum 被声明为全局变量并且多个线程正在更新它。任何人都可以解释为什么这里的线程在没有锁的共享变量上工作得很好吗?

代码如下:

    #include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

#define NTHREADS      100
#define ARRAYSIZE   1000000
#define ITERATIONS   ARRAYSIZE / NTHREADS

double  sum=0.0, a[ARRAYSIZE];
pthread_mutex_t sum_mutex;


void *do_work(void *tid) 
{
  int i, start, *mytid, end;
  double mysum=0.0;

  /* Initialize my part of the global array and keep local sum */
  mytid = (int *) tid;
  start = (*mytid * ITERATIONS);
  end = start + ITERATIONS;
  printf ("Thread %d doing iterations %d to %d\n",*mytid,start,end-1); 
  for (i=start; i < end ; i++) {
    a[i] = i * 1.0;
    mysum = mysum + a[i];
    }

  /* Lock the mutex and update the global sum, then exit */
  //pthread_mutex_lock (&sum_mutex);  //here I tried not to use locks
  sum = sum + mysum;
  //pthread_mutex_unlock (&sum_mutex);
  pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
  int i, start, tids[NTHREADS];
  pthread_t threads[NTHREADS];
  pthread_attr_t attr;

  /* Pthreads setup: initialize mutex and explicitly create threads in a
     joinable state (for portability).  Pass each thread its loop offset */
  pthread_mutex_init(&sum_mutex, NULL);
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  for (i=0; i<NTHREADS; i++) {
    tids[i] = i;
    pthread_create(&threads[i], &attr, do_work, (void *) &tids[i]);
    }

  /* Wait for all threads to complete then print global sum */ 
  for (i=0; i<NTHREADS; i++) {
    pthread_join(threads[i], NULL);
  }
  printf ("Done. Sum= %e \n", sum);

  sum=0.0;
  for (i=0;i<ARRAYSIZE;i++){ 
  a[i] = i*1.0;
  sum = sum + a[i]; }
  printf("Check Sum= %e\n",sum);

  /* Clean up and exit */
  pthread_attr_destroy(&attr);
  pthread_mutex_destroy(&sum_mutex);
  pthread_exit (NULL);
}

带锁和不带锁我得到的答案都是一样的!

Done. Sum= 4.999995e+11 
Check Sum= 4.999995e+11

更新:用户 3386109

建议的更改
for (i=start; i < end ; i++) {
a[i] = i * 1.0;
//pthread_mutex_lock (&sum_mutex);
sum = sum + a[i];
 //pthread_mutex_lock (&sum_mutex); 
}

效果:

    Done. Sum= 3.878172e+11 
   Check Sum= 4.999995e+11

互斥体用于防止竞争条件,当您有两个或多个线程访问共享资源时,这是不希望出现的情况。当共享变量 sum 被多个线程访问时,就会发生诸如代码中的竞争条件。有时对共享变量的访问会交错,结果不正确,有时结果正确。

例如,假设您有两个线程,线程 A 和线程 B 都将 1 添加到共享值 sum,从 5 开始。如果线程 A 读取 sum,然后线程B 读取 sum,然后线程 A 写入一个新值,然后线程 B 写入一个新值,您将得到一个不正确的结果,6 而不是 7。但是,线程 A 读取然后写入一个值也是可能的(特别是 6),然后线程 B 读取和写入一个值(特别是 7),然后你得到正确的结果。关键是一些操作交错会产生正确的值,而一些交错会导致不正确的值。互斥量的工作是强制交错始终正确。