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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM