加入收藏 | 设为首页 | 会员中心 | 我要投稿 晋中站长网 (https://www.0354zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 移动互联 > 评测 > 正文

面试多线程同步,你必须要思考的问题

发布时间:2019-07-31 16:41:07 所属栏目:评测 来源:佚名
导读:ReentrantLock的实现网上有很多文章了,本篇文章会简单介绍下其java层实现,重点放在分析竞争锁失败后如何阻塞线程。 因篇幅有限,synchronized的内容将会放到下篇文章。 Java Lock的实现 ReentrantLock是jdk中常用的锁实现,其实现逻辑主语基于AQS(juc包

pthread_cond_timedwait用于阻塞线程,实现线程等待, 代码在glibc的pthread_cond_timedwait.c文件中,代码较长,你可以先简单过一遍,看完下面的分析再重新读一遍代码

  1. int 
  2. int 
  3. __pthread_cond_timedwait (cond, mutex, abstime) 
  4.  pthread_cond_t *cond; 
  5.  pthread_mutex_t *mutex; 
  6.  const struct timespec *abstime; 
  7.  struct _pthread_cleanup_buffer buffer; 
  8.  struct _condvar_cleanup_buffer cbuffer; 
  9.  int result = 0; 
  10.  /* Catch invalid parameters. */ 
  11.  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) 
  12.  return EINVAL; 
  13.  int pshared = (cond->__data.__mutex == (void *) ~0l) 
  14.  ? LLL_SHARED : LLL_PRIVATE; 
  15.  //1.获得cond锁 
  16.  lll_lock (cond->__data.__lock, pshared); 
  17.  //2.释放mutex锁 
  18.  int err = __pthread_mutex_unlock_usercnt (mutex, 0); 
  19.  if (err) 
  20.  { 
  21.  lll_unlock (cond->__data.__lock, pshared); 
  22.  return err; 
  23.  } 
  24.  /* We have one new user of the condvar. */ 
  25.  //每执行一次wait(pthread_cond_timedwait/pthread_cond_wait),__total_seq就会+1 
  26.  ++cond->__data.__total_seq; 
  27.  //用来执行futex_wait的变量 
  28.  ++cond->__data.__futex; 
  29.  //标识该cond还有多少线程在使用,pthread_cond_destroy需要等待所有的操作完成 
  30.  cond->__data.__nwaiters += 1 << COND_NWAITERS_SHIFT; 
  31.  /* Remember the mutex we are using here. If there is already a 
  32.  different address store this is a bad user bug. Do not store 
  33.  anything for pshared condvars. */ 
  34.  //保存mutex锁 
  35.  if (cond->__data.__mutex != (void *) ~0l) 
  36.  cond->__data.__mutex = mutex; 
  37.  /* Prepare structure passed to cancellation handler. */ 
  38.  cbuffer.cond = cond; 
  39.  cbuffer.mutex = mutex; 
  40.  /* Before we block we enable cancellation. Therefore we have to 
  41.  install a cancellation handler. */ 
  42.  __pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer); 
  43.  /* The current values of the wakeup counter. The "woken" counter 
  44.  must exceed this value. */ 
  45.  //记录futex_wait前的__wakeup_seq(为该cond上执行了多少次sign操作+timeout次数)和__broadcast_seq(代表在该cond上执行了多少次broadcast) 
  46.  unsigned long long int val; 
  47.  unsigned long long int seq; 
  48.  val = seq = cond->__data.__wakeup_seq; 
  49.  /* Remember the broadcast counter. */ 
  50.  cbuffer.bc_seq = cond->__data.__broadcast_seq; 
  51.  while (1) 
  52.  { 
  53.  //3.计算要wait的相对时间 
  54.  struct timespec rt; 
  55.  { 
  56. #ifdef __NR_clock_gettime 
  57.  INTERNAL_SYSCALL_DECL (err); 
  58.  int ret; 
  59.  ret = INTERNAL_VSYSCALL (clock_gettime, err, 2, 
  60.  (cond->__data.__nwaiters 
  61.  & ((1 << COND_NWAITERS_SHIFT) - 1)), 
  62.  &rt); 
  63. # ifndef __ASSUME_POSIX_TIMERS 
  64.  if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (ret, err), 0)) 
  65.  { 
  66.  struct timeval tv; 
  67.  (void) gettimeofday (&tv, NULL); 
  68.  /* Convert the absolute timeout value to a relative timeout. */ 
  69.  rt.tv_sec = abstime->tv_sec - tv.tv_sec; 
  70.  rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; 
  71.  } 
  72.  else 
  73. # endif 
  74.  { 
  75.  /* Convert the absolute timeout value to a relative timeout. */ 
  76.  rt.tv_sec = abstime->tv_sec - rt.tv_sec; 
  77.  rt.tv_nsec = abstime->tv_nsec - rt.tv_nsec; 
  78.  } 
  79. #else 
  80.  /* Get the current time. So far we support only one clock. */ 
  81.  struct timeval tv; 
  82.  (void) gettimeofday (&tv, NULL); 
  83.  /* Convert the absolute timeout value to a relative timeout. */ 
  84.  rt.tv_sec = abstime->tv_sec - tv.tv_sec; 
  85.  rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; 
  86. #endif 
  87.  } 
  88.  if (rt.tv_nsec < 0) 
  89.  { 
  90.  rt.tv_nsec += 1000000000; 
  91.  --rt.tv_sec; 
  92.  } 
  93.  /*---计算要wait的相对时间 end---- */ 
  94.  //是否超时 
  95.  /* Did we already time out? */ 
  96.  if (__builtin_expect (rt.tv_sec < 0, 0)) 
  97.  { 
  98.  //被broadcast唤醒,这里疑问的是,为什么不需要判断__wakeup_seq? 
  99.  if (cbuffer.bc_seq != cond->__data.__broadcast_seq) 
  100.  goto bc_out; 
  101.  goto timeout; 
  102.  } 
  103.  unsigned int futex_val = cond->__data.__futex; 
  104.  //4.释放cond锁,准备wait 
  105.  lll_unlock (cond->__data.__lock, pshared); 
  106.  /* Enable asynchronous cancellation. Required by the standard. */ 
  107.  cbuffer.oldtype = __pthread_enable_asynccancel (); 
  108.  //5.调用futex_wait 
  109.  /* Wait until woken by signal or broadcast. */ 
  110.  err = lll_futex_timed_wait (&cond->__data.__futex, 
  111.  futex_val, &rt, pshared); 
  112.  /* Disable asynchronous cancellation. */ 
  113.  __pthread_disable_asynccancel (cbuffer.oldtype); 
  114.  //6.重新获得cond锁,因为又要访问&修改cond的数据了 
  115.  lll_lock (cond->__data.__lock, pshared); 
  116.  //__broadcast_seq值发生改变,代表发生了有线程调用了广播 
  117.  if (cbuffer.bc_seq != cond->__data.__broadcast_seq) 
  118.  goto bc_out; 
  119.  //判断是否是被sign唤醒的,sign会增加__wakeup_seq 
  120.  //第二个条件cond->__data.__woken_seq != val的意义在于 
  121.  //可能两个线程A、B在wait,一个线程调用了sign导致A被唤醒,这时B因为超时被唤醒 
  122.  //对于B线程来说,执行到这里时第一个条件也是满足的,从而导致上层拿到的result不是超时 
  123.  //所以这里需要判断下__woken_seq(即该cond已经被唤醒的线程数)是否等于__wakeup_seq(sign执行次数+timeout次数) 
  124.  val = cond->__data.__wakeup_seq; 
  125.  if (val != seq && cond->__data.__woken_seq != val) 
  126.  break; 
  127.  /* Not woken yet. Maybe the time expired? */ 
  128.  if (__builtin_expect (err == -ETIMEDOUT, 0)) 
  129.  { 
  130.  timeout: 
  131.  /* Yep. Adjust the counters. */ 
  132.  ++cond->__data.__wakeup_seq; 
  133.  ++cond->__data.__futex; 
  134.  /* The error value. */ 
  135.  result = ETIMEDOUT; 
  136.  break; 
  137.  } 
  138.  } 
  139.  //一个线程已经醒了所以这里__woken_seq +1 
  140.  ++cond->__data.__woken_seq; 
  141.  bc_out: 
  142.  // 
  143.  cond->__data.__nwaiters -= 1 << COND_NWAITERS_SHIFT; 
  144.  /* If pthread_cond_destroy was called on this variable already, 
  145.  notify the pthread_cond_destroy caller all waiters have left 
  146.  and it can be successfully destroyed. */ 
  147.  if (cond->__data.__total_seq == -1ULL 
  148.  && cond->__data.__nwaiters < (1 << COND_NWAITERS_SHIFT)) 
  149.  lll_futex_wake (&cond->__data.__nwaiters, 1, pshared); 
  150.  //9.cond数据修改完毕,释放锁 
  151.  lll_unlock (cond->__data.__lock, pshared); 
  152.  /* The cancellation handling is back to normal, remove the handler. */ 
  153.  __pthread_cleanup_pop (&buffer, 0); 
  154.  //10.重新获得mutex锁 
  155.  err = __pthread_mutex_cond_lock (mutex); 
  156.  return err ?: result; 

(编辑:晋中站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读