| 
                         pthread_cond_timedwait用于阻塞线程,实现线程等待,  代码在glibc的pthread_cond_timedwait.c文件中,代码较长,你可以先简单过一遍,看完下面的分析再重新读一遍代码 
- int 
 - int 
 - __pthread_cond_timedwait (cond, mutex, abstime) 
 -  pthread_cond_t *cond; 
 -  pthread_mutex_t *mutex; 
 -  const struct timespec *abstime; 
 - { 
 -  struct _pthread_cleanup_buffer buffer; 
 -  struct _condvar_cleanup_buffer cbuffer; 
 -  int result = 0; 
 -  /* Catch invalid parameters. */ 
 -  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) 
 -  return EINVAL; 
 -  int pshared = (cond->__data.__mutex == (void *) ~0l) 
 -  ? LLL_SHARED : LLL_PRIVATE; 
 -  //1.获得cond锁 
 -  lll_lock (cond->__data.__lock, pshared); 
 -  //2.释放mutex锁 
 -  int err = __pthread_mutex_unlock_usercnt (mutex, 0); 
 -  if (err) 
 -  { 
 -  lll_unlock (cond->__data.__lock, pshared); 
 -  return err; 
 -  } 
 -  /* We have one new user of the condvar. */ 
 -  //每执行一次wait(pthread_cond_timedwait/pthread_cond_wait),__total_seq就会+1 
 -  ++cond->__data.__total_seq; 
 -  //用来执行futex_wait的变量 
 -  ++cond->__data.__futex; 
 -  //标识该cond还有多少线程在使用,pthread_cond_destroy需要等待所有的操作完成 
 -  cond->__data.__nwaiters += 1 << COND_NWAITERS_SHIFT; 
 -  /* Remember the mutex we are using here. If there is already a 
 -  different address store this is a bad user bug. Do not store 
 -  anything for pshared condvars. */ 
 -  //保存mutex锁 
 -  if (cond->__data.__mutex != (void *) ~0l) 
 -  cond->__data.__mutex = mutex; 
 -  /* Prepare structure passed to cancellation handler. */ 
 -  cbuffer.cond = cond; 
 -  cbuffer.mutex = mutex; 
 -  /* Before we block we enable cancellation. Therefore we have to 
 -  install a cancellation handler. */ 
 -  __pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer); 
 -  /* The current values of the wakeup counter. The "woken" counter 
 -  must exceed this value. */ 
 -  //记录futex_wait前的__wakeup_seq(为该cond上执行了多少次sign操作+timeout次数)和__broadcast_seq(代表在该cond上执行了多少次broadcast) 
 -  unsigned long long int val; 
 -  unsigned long long int seq; 
 -  val = seq = cond->__data.__wakeup_seq; 
 -  /* Remember the broadcast counter. */ 
 -  cbuffer.bc_seq = cond->__data.__broadcast_seq; 
 -  while (1) 
 -  { 
 -  //3.计算要wait的相对时间 
 -  struct timespec rt; 
 -  { 
 - #ifdef __NR_clock_gettime 
 -  INTERNAL_SYSCALL_DECL (err); 
 -  int ret; 
 -  ret = INTERNAL_VSYSCALL (clock_gettime, err, 2, 
 -  (cond->__data.__nwaiters 
 -  & ((1 << COND_NWAITERS_SHIFT) - 1)), 
 -  &rt); 
 - # ifndef __ASSUME_POSIX_TIMERS 
 -  if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (ret, err), 0)) 
 -  { 
 -  struct timeval tv; 
 -  (void) gettimeofday (&tv, NULL); 
 -  /* Convert the absolute timeout value to a relative timeout. */ 
 -  rt.tv_sec = abstime->tv_sec - tv.tv_sec; 
 -  rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; 
 -  } 
 -  else 
 - # endif 
 -  { 
 -  /* Convert the absolute timeout value to a relative timeout. */ 
 -  rt.tv_sec = abstime->tv_sec - rt.tv_sec; 
 -  rt.tv_nsec = abstime->tv_nsec - rt.tv_nsec; 
 -  } 
 - #else 
 -  /* Get the current time. So far we support only one clock. */ 
 -  struct timeval tv; 
 -  (void) gettimeofday (&tv, NULL); 
 -  /* Convert the absolute timeout value to a relative timeout. */ 
 -  rt.tv_sec = abstime->tv_sec - tv.tv_sec; 
 -  rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; 
 - #endif 
 -  } 
 -  if (rt.tv_nsec < 0) 
 -  { 
 -  rt.tv_nsec += 1000000000; 
 -  --rt.tv_sec; 
 -  } 
 -  /*---计算要wait的相对时间 end---- */ 
 -  //是否超时 
 -  /* Did we already time out? */ 
 -  if (__builtin_expect (rt.tv_sec < 0, 0)) 
 -  { 
 -  //被broadcast唤醒,这里疑问的是,为什么不需要判断__wakeup_seq? 
 -  if (cbuffer.bc_seq != cond->__data.__broadcast_seq) 
 -  goto bc_out; 
 -  goto timeout; 
 -  } 
 -  unsigned int futex_val = cond->__data.__futex; 
 -  //4.释放cond锁,准备wait 
 -  lll_unlock (cond->__data.__lock, pshared); 
 -  /* Enable asynchronous cancellation. Required by the standard. */ 
 -  cbuffer.oldtype = __pthread_enable_asynccancel (); 
 -  //5.调用futex_wait 
 -  /* Wait until woken by signal or broadcast. */ 
 -  err = lll_futex_timed_wait (&cond->__data.__futex, 
 -  futex_val, &rt, pshared); 
 -  /* Disable asynchronous cancellation. */ 
 -  __pthread_disable_asynccancel (cbuffer.oldtype); 
 -  //6.重新获得cond锁,因为又要访问&修改cond的数据了 
 -  lll_lock (cond->__data.__lock, pshared); 
 -  //__broadcast_seq值发生改变,代表发生了有线程调用了广播 
 -  if (cbuffer.bc_seq != cond->__data.__broadcast_seq) 
 -  goto bc_out; 
 -  //判断是否是被sign唤醒的,sign会增加__wakeup_seq 
 -  //第二个条件cond->__data.__woken_seq != val的意义在于 
 -  //可能两个线程A、B在wait,一个线程调用了sign导致A被唤醒,这时B因为超时被唤醒 
 -  //对于B线程来说,执行到这里时第一个条件也是满足的,从而导致上层拿到的result不是超时 
 -  //所以这里需要判断下__woken_seq(即该cond已经被唤醒的线程数)是否等于__wakeup_seq(sign执行次数+timeout次数) 
 -  val = cond->__data.__wakeup_seq; 
 -  if (val != seq && cond->__data.__woken_seq != val) 
 -  break; 
 -  /* Not woken yet. Maybe the time expired? */ 
 -  if (__builtin_expect (err == -ETIMEDOUT, 0)) 
 -  { 
 -  timeout: 
 -  /* Yep. Adjust the counters. */ 
 -  ++cond->__data.__wakeup_seq; 
 -  ++cond->__data.__futex; 
 -  /* The error value. */ 
 -  result = ETIMEDOUT; 
 -  break; 
 -  } 
 -  } 
 -  //一个线程已经醒了所以这里__woken_seq +1 
 -  ++cond->__data.__woken_seq; 
 -  bc_out: 
 -  // 
 -  cond->__data.__nwaiters -= 1 << COND_NWAITERS_SHIFT; 
 -  /* If pthread_cond_destroy was called on this variable already, 
 -  notify the pthread_cond_destroy caller all waiters have left 
 -  and it can be successfully destroyed. */ 
 -  if (cond->__data.__total_seq == -1ULL 
 -  && cond->__data.__nwaiters < (1 << COND_NWAITERS_SHIFT)) 
 -  lll_futex_wake (&cond->__data.__nwaiters, 1, pshared); 
 -  //9.cond数据修改完毕,释放锁 
 -  lll_unlock (cond->__data.__lock, pshared); 
 -  /* The cancellation handling is back to normal, remove the handler. */ 
 -  __pthread_cleanup_pop (&buffer, 0); 
 -  //10.重新获得mutex锁 
 -  err = __pthread_mutex_cond_lock (mutex); 
 -  return err ?: result; 
 - } 
 
                          (编辑:泰州站长网) 
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! 
                     |