【问题标题】:Why does this code work without a mutex?为什么这段代码在没有互斥锁的情况下工作?
【发布时间】:2015-09-17 22:58:44
【问题描述】:

我正在尝试学习锁在多线程中的工作原理。当我在没有锁的情况下执行以下代码时,即使变量 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

更新:user3386109 建议的更改

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

【问题讨论】:

  • 欢迎来到并发世界。比赛条件取决于时间。有时它可能会“起作用”,因为它会产生正确的结果。但是代码仍然是错误的,因为如果你运行它更多次,使用更多线程或在不同的系统上,那么有时它会失败。这称为非确定性行为。
  • 类比:我制造了一个太空火箭,它成功地发射了,有没有几个螺丝到位。这是否意味着不需要这些螺丝?不,这意味着我很幸运,太空火箭随时可能失败。
  • 尝试不使用局部变量mysum。更新for循环中的全局sum,看看有没有效果。

标签: c multithreading locking pthreads


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 2015-09-06
    • 1970-01-01
    • 2021-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-28
    • 1970-01-01
    • 2015-10-11
    相关资源
    最近更新 更多