pthread_mutex_lock源码分析

直接把注释写到代码中:

int
__pthread_mutex_lock (pthread_mutex_t *mutex)
{
  unsigned int type = PTHREAD_MUTEX_TYPE_ELISION (mutex);

  //安全检查
  LIBC_PROBE (mutex_entry, 1, mutex);

  //返回 __pthread_mutex_lock_full
  if (__builtin_expect (type & ~(PTHREAD_MUTEX_KIND_MASK_NP
                 | PTHREAD_MUTEX_ELISION_FLAGS_NP), 0))
    return __pthread_mutex_lock_full (mutex);

  //普通锁
  if (__glibc_likely (type == PTHREAD_MUTEX_TIMED_NP))
    {
      FORCE_ELISION (mutex, goto elision);
    simple:
      /* Normal mutex.  */
      //LLL_MUTEX_LOCK 通过原子操作将0变为1,失败阻塞
      /*
      最终调用的是__lll_lock:
      #define __lll_lock(futex, private)                                      \
        ((void)                                                               \
         ({                                                                   \
           int *__futex = (futex);                                              \
           if (__glibc_unlikely                                               \
               (atomic_compare_and_exchange_bool_acq (__futex, 1, 0)))          \
             {                                                                  \
               if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \
                 __lll_lock_wait_private (__futex);                           \
               else                                                           \
                 __lll_lock_wait (__futex, private);                          \
             }                                                                  \
         }))

      阻塞的实现(futex系统调用):
      #define lll_futex_syscall(nargs, futexp, op, ...)                       \
      ({                                                                    \
        INTERNAL_SYSCALL_DECL (__err);                                      \
        long int __ret = INTERNAL_SYSCALL (futex, __err, nargs, futexp, op, \
                           __VA_ARGS__);                    \
        (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (__ret, __err))         \
         ? -INTERNAL_SYSCALL_ERRNO (__ret, __err) : 0);                     \
      })

      */
      LLL_MUTEX_LOCK (mutex);
      //获取失败中断
      assert (mutex->__data.__owner == 0);
    }
#ifdef HAVE_ELISION
  else if (__glibc_likely (type == PTHREAD_MUTEX_TIMED_ELISION_NP))
    {
  elision: __attribute__((unused))
      /* This case can never happen on a system without elision,
         as the mutex type initialization functions will not
     allow to set the elision flags.  */
      /* Don't record owner or users for elision case.  This is a
         tail call.  */
      return LLL_MUTEX_LOCK_ELISION (mutex);
    }
#endif

    //自旋锁
  else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex)
                 == PTHREAD_MUTEX_RECURSIVE_NP, 1))
    {
    //获取线程id
      pid_t id = THREAD_GETMEM (THREAD_SELF, tid);

     //已经持有锁直接返回
      if (mutex->__data.__owner == id)
    {
      //防止计数溢出
      if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
        /* Overflow of the counter.  */
        return EAGAIN;

      //计数加一
      ++mutex->__data.__count;

      return 0;
    }

      //获取锁
      LLL_MUTEX_LOCK (mutex);

      assert (mutex->__data.__owner == 0);
      mutex->__data.__count = 1;
    }
  //适应锁 等待解锁后重新竞争
  else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex)
              == PTHREAD_MUTEX_ADAPTIVE_NP, 1))
    {
      if (! __is_smp)
    goto simple;

      if (LLL_MUTEX_TRYLOCK (mutex) != 0)
    {
      int cnt = 0;
      int max_cnt = MIN (MAX_ADAPTIVE_COUNT,
                 mutex->__data.__spins * 2 + 10);
      //循环等待获得锁
      do
        {
          if (cnt++ >= max_cnt)
        {
          LLL_MUTEX_LOCK (mutex);
          break;
        }
          atomic_spin_nop ();
        }
      while (LLL_MUTEX_TRYLOCK (mutex) != 0);

      mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8;
    }
      assert (mutex->__data.__owner == 0);
    }
  //检错锁
  else
    {
      pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
      assert (PTHREAD_MUTEX_TYPE (mutex) == PTHREAD_MUTEX_ERRORCHECK_NP);
      //线程持有锁返回EDEADLK
      if (__glibc_unlikely (mutex->__data.__owner == id))
    return EDEADLK;
      //跳转到普通锁加锁
      goto simple;
    }

  pid_t id = THREAD_GETMEM (THREAD_SELF, tid);

  //记录线程id
  mutex->__data.__owner = id;
#ifndef NO_INCR
  ++mutex->__data.__nusers;
#endif

  LIBC_PROBE (mutex_acquired, 1, mutex);

  return 0;
}

 

posted @ 2020-06-20 20:49  wa小怪兽  阅读(2978)  评论(0编辑  收藏  举报