pthread_mutex_lock源码分析

Posted hadesblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pthread_mutex_lock源码分析相关的知识,希望对你有一定的参考价值。

直接把注释写到代码中:

  1 int
  2 __pthread_mutex_lock (pthread_mutex_t *mutex)
  3 {
  4   unsigned int type = PTHREAD_MUTEX_TYPE_ELISION (mutex);
  5 
  6   //安全检查
  7   LIBC_PROBE (mutex_entry, 1, mutex);
  8 
  9   //返回 __pthread_mutex_lock_full
 10   if (__builtin_expect (type & ~(PTHREAD_MUTEX_KIND_MASK_NP
 11                  | PTHREAD_MUTEX_ELISION_FLAGS_NP), 0))
 12     return __pthread_mutex_lock_full (mutex);
 13 
 14   //普通锁
 15   if (__glibc_likely (type == PTHREAD_MUTEX_TIMED_NP))
 16     {
 17       FORCE_ELISION (mutex, goto elision);
 18     simple:
 19       /* Normal mutex.  */
 20       //LLL_MUTEX_LOCK 通过原子操作将0变为1,失败阻塞
 21       /*
 22       最终调用的是__lll_lock:
 23       #define __lll_lock(futex, private)                                       24         ((void)                                                                25          ({                                                                    26            int *__futex = (futex);                                               27            if (__glibc_unlikely                                                28                (atomic_compare_and_exchange_bool_acq (__futex, 1, 0)))           29              {                                                                   30                if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)  31                  __lll_lock_wait_private (__futex);                            32                else                                                            33                  __lll_lock_wait (__futex, private);                           34              }                                                                   35          }))
 36 
 37       阻塞的实现(futex系统调用):
 38       #define lll_futex_syscall(nargs, futexp, op, ...)                        39       ({                                                                     40         INTERNAL_SYSCALL_DECL (__err);                                       41         long int __ret = INTERNAL_SYSCALL (futex, __err, nargs, futexp, op,  42                            __VA_ARGS__);                     43         (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (__ret, __err))          44          ? -INTERNAL_SYSCALL_ERRNO (__ret, __err) : 0);                      45       })
 46       
 47       */
 48       LLL_MUTEX_LOCK (mutex);
 49       //获取失败中断
 50       assert (mutex->__data.__owner == 0);
 51     }
 52 #ifdef HAVE_ELISION
 53   else if (__glibc_likely (type == PTHREAD_MUTEX_TIMED_ELISION_NP))
 54     {
 55   elision: __attribute__((unused))
 56       /* This case can never happen on a system without elision,
 57          as the mutex type initialization functions will not
 58      allow to set the elision flags.  */
 59       /* Don‘t record owner or users for elision case.  This is a
 60          tail call.  */
 61       return LLL_MUTEX_LOCK_ELISION (mutex);
 62     }
 63 #endif
 64 
 65     //自旋锁
 66   else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex)
 67                  == PTHREAD_MUTEX_RECURSIVE_NP, 1))
 68     {
 69     //获取线程id
 70       pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
 71 
 72      //已经持有锁直接返回
 73       if (mutex->__data.__owner == id)
 74     {
 75       //防止计数溢出
 76       if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
 77         /* Overflow of the counter.  */
 78         return EAGAIN;
 79 
 80       //计数加一
 81       ++mutex->__data.__count;
 82 
 83       return 0;
 84     }
 85 
 86       //获取锁
 87       LLL_MUTEX_LOCK (mutex);
 88 
 89       assert (mutex->__data.__owner == 0);
 90       mutex->__data.__count = 1;
 91     }
 92   //适应锁 等待解锁后重新竞争
 93   else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex)
 94               == PTHREAD_MUTEX_ADAPTIVE_NP, 1))
 95     {
 96       if (! __is_smp)
 97     goto simple;
 98 
 99       if (LLL_MUTEX_TRYLOCK (mutex) != 0)
100     {
101       int cnt = 0;
102       int max_cnt = MIN (MAX_ADAPTIVE_COUNT,
103                  mutex->__data.__spins * 2 + 10);
104       //循环等待获得锁
105       do
106         {
107           if (cnt++ >= max_cnt)
108         {
109           LLL_MUTEX_LOCK (mutex);
110           break;
111         }
112           atomic_spin_nop ();
113         }
114       while (LLL_MUTEX_TRYLOCK (mutex) != 0);
115 
116       mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8;
117     }
118       assert (mutex->__data.__owner == 0);
119     }
120   //检错锁
121   else
122     {
123       pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
124       assert (PTHREAD_MUTEX_TYPE (mutex) == PTHREAD_MUTEX_ERRORCHECK_NP);
125       //线程持有锁返回EDEADLK
126       if (__glibc_unlikely (mutex->__data.__owner == id))
127     return EDEADLK;
128       //跳转到普通锁加锁
129       goto simple;
130     }
131 
132   pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
133 
134   //记录线程id
135   mutex->__data.__owner = id;
136 #ifndef NO_INCR
137   ++mutex->__data.__nusers;
138 #endif
139 
140   LIBC_PROBE (mutex_acquired, 1, mutex);
141 
142   return 0;
143 }

 

 

以上是关于pthread_mutex_lock源码分析的主要内容,如果未能解决你的问题,请参考以下文章

ThreadX内核源码分析 - 定时器及线程时间片调度(arm)

Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | DexFile loadDexFile 函数 | 构造函数 | openDexFile 函数 )(代码片

AtomicInteger源码分析——基于CAS的乐观锁实

pthread_join 和 pthread_mutex_lock 有啥区别?

源码分析系列x264_nal_dataflow

pthread_mutex_lock 导致死锁