zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    初学AOP
    通过工厂方式配置bean
    Spring中Bean的生命周期方法
    Spring中配置文件中引用外部文件
    Spring中的SPEL
    Spring中的自动装配
    初学Spring
    暑假写的有关字符串处理的程序
    linux查看所有用户信息
    python 函数enumerate(x,y)的用法
  • 原文地址:https://www.cnblogs.com/HadesBlog/p/13170298.html
Copyright © 2011-2022 走看看