本文介绍了如何知道一个锁到底被哪个线程占用(下)?求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。
对技术面试,学习经验等有一些体会,在此分享。
- 问题
- 常用的锁
- os_unfair_lock
- 简单介绍
- 追溯锁的拥有者
问题
在iOS开发调试的过程中,有时会发现app卡死了,点击 pause program execution
暂停程序,会发现程序停到等待某个锁上面。如果程序停止在咱自己的代码上面还好排查一点。如果停在没有源码的第三方库或者系统库中,这就不好排查问题了。
这里有一个小方法,可能会提供一点帮助。那就是找到这个锁被那个线程占用了。
常用的锁
iOS中有很多锁,目前比较常用的有 pthread_mutex
、NSLock
、os_unfair_lock
、@synchronized
和dispatch_semaphore
。但不是所有的锁都能找到其被哪个线程所拥有。
目前我知道的能找到其拥有者的锁是 pthread_mutex_t
、os_unfair_lock
以及基于这二者实现的其他上层 API,包括dispatch_once
、NSLock
,NSRecursiveLock
,@synchronized
。
其中dispatch_once
的实现是基于 os_unfair_lock
,剩下的实现是基于pthread_mutex_t
os_unfair_lock
简单介绍
os_unfair_lock
是一个低等级锁, 设计宗旨是用于替换 OSSpinLock
,从 iOS 10
之后开始支持,跟 OSSpinLock
不同,等待 os_unfair_lock
的线程会处于休眠状态.
使用时首先要引入头文件#import
os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;//必须这么初始化 os_unfair_lock_lock(&lock);//加锁 //临界区 os_unfair_lock_unlock(&lock);//解锁
追溯锁的拥有者
os_unfair_lock 是一个结构体
typedef struct os_unfair_lock_s { uint32_t _os_unfair_lock_opaque; } os_unfair_lock, *os_unfair_lock_t;
初始化就是把 _os_unfair_lock_opaque 赋值为零
(lldb) p _lock (os_unfair_lock) $0 = (_os_unfair_lock_opaque = 0)
执行加锁代码后再次查看
(lldb) p _lock (os_unfair_lock) $4 = (_os_unfair_lock_opaque = 4358)
(4358 的十六进制是0x1106)
从google上搜 os_unfair_lock_lock site:opensource.apple.com 能找到开源代码libplatform,我看的是220.100.1
这一版
#ifndef __TSD_MACH_THREAD_SELF #define __TSD_MACH_THREAD_SELF 3 #endif static void _os_unfair_lock_lock_slow(_os_unfair_lock_t l, os_lock_owner_t self, os_unfair_lock_options_t options) { os_unfair_lock_options_t allow_anonymous_owner = options & OS_UNFAIR_LOCK_ALLOW_ANONYMOUS_OWNER; options &= ~OS_UNFAIR_LOCK_ALLOW_ANONYMOUS_OWNER; if (unlikely(options & ~OS_UNFAIR_LOCK_OPTIONS_MASK)) { __LIBPLATFORM_CLIENT_CRASH__(options, "Invalid options"); } os_ulock_value_t current, new, waiters_mask = 0; ......//删除了第一次加锁不会走到的代码 new = self & ~waiters_mask; bool r = os_atomic_cmpxchgv2o(l, oul_value, OS_LOCK_NO_OWNER, new, ¤t, acquire); if (unlikely(!r)) goto _retry; } void os_unfair_lock_lock(os_unfair_lock_t lock) { _os_unfair_lock_t l = (_os_unfair_lock_t)lock; os_lock_owner_t self = _os_lock_owner_get_self(); bool r = os_atomic_cmpxchg2o(l, oul_value, OS_LOCK_NO_OWNER, self, acquire); if (likely(r)) return; return _os_unfair_lock_lock_slow(l, self, OS_UNFAIR_LOCK_NONE); } static inline os_lock_owner_t _os_lock_owner_get_self(void) { os_lock_owner_t self; self = (os_lock_owner_t)_os_tsd_get_direct(__TSD_MACH_THREAD_SELF); return self; }
先把关注点放在 _os_lock_owner_get_self
函数。
_os_tsd_get_direct
也能找到源码,
static __inline__ void* _os_tsd_get_direct(unsigned long slot) { void *ret; __asm__("mov %%gs:%1, %0" : "=r" (ret) : "m" (*(void **)(slot * sizeof(void *)))); return ret; }
很幸运的是在开源代码 libpthread里发现了下面的代码
void * _pthread_getspecific_direct(unsigned long slot) { #if TARGET_IPHONE_SIMULATOR return pthread_getspecific(slot); #else return _os_tsd_get_direct(slot); #endif }
pthread_getspecific
函数在咱引用 #import <pthread.h>
后是可以调用的。
void * owner = pthread_getspecific(3);
做过实验后发现 owner & ~waiters_mask;
正好等于 _os_unfair_lock_opaque 的值。
现在就找到了os_unfair_lock与线程相关的值。
也可以看一下 os_unfair_lock_assert_owner 函数的源码,该函数是判断当前线程是否是 os_unfair_lock 的所有者,否则触发断言。
“`
- 问题
- 常用的锁
- os_unfair_lock
- 简单介绍
- 追溯锁的拥有者
问题
在iOS开发调试的过程中,有时会发现app卡死了,点击 pause program execution
暂停程序,会发现程序停到等待某个锁上面。如果程序停止在咱自己的代码上面还好排查一点。如果停在没有源码的第三方库或者系统库中,这就不好排查问题了。
这里有一个小方法,可能会提供一点帮助。那就是找到这个锁被那个线程占用了。
常用的锁
iOS中有很多锁,目前比较常用的有 pthread_mutex
、NSLock
、os_unfair_lock
、@synchronized
和dispatch_semaphore
。但不是所有的锁都能找到其被哪个线程所拥有。
目前我知道的能找到其拥有者的锁是 pthread_mutex_t
、os_unfair_lock
以及基于这二者实现的其他上层 API,包括dispatch_once
、NSLock
,NSRecursiveLock
,@synchronized
。
其中dispatch_once
的实现是基于 os_unfair_lock
,剩下的实现是基于pthread_mutex_t
os_unfair_lock
简单介绍
os_unfair_lock
是一个低等级锁, 设计宗旨是用于替换 OSSpinLock
,从 iOS 10
之后开始支持,跟 OSSpinLock
不同,等待 os_unfair_lock
的线程会处于休眠状态.
使用时首先要引入头文件#import
os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;//必须这么初始化 os_unfair_lock_lock(&lock);//加锁 //临界区 os_unfair_lock_unlock(&lock);//解锁
追溯锁的拥有者
os_unfair_lock 是一个结构体
typedef struct os_unfair_lock_s { uint32_t _os_unfair_lock_opaque; } os_unfair_lock, *os_unfair_lock_t;
初始化就是把 _os_unfair_lock_opaque 赋值为零
(lldb) p _lock (os_unfair_lock) $0 = (_os_unfair_lock_opaque = 0)
执行加锁代码后再次查看
(lldb) p _lock (os_unfair_lock) $4 = (_os_unfair_lock_opaque = 4358)
(4358 的十六进制是0x1106)
从google上搜 os_unfair_lock_lock site:opensource.apple.com 能找到开源代码libplatform,我看的是220.100.1
这一版
#ifndef __TSD_MACH_THREAD_SELF #define __TSD_MACH_THREAD_SELF 3 #endif static void _os_unfair_lock_lock_slow(_os_unfair_lock_t l, os_lock_owner_t self, os_unfair_lock_options_t options) { os_unfair_lock_options_t allow_anonymous_owner = options & OS_UNFAIR_LOCK_ALLOW_ANONYMOUS_OWNER; options &= ~OS_UNFAIR_LOCK_ALLOW_ANONYMOUS_OWNER; if (unlikely(options & ~OS_UNFAIR_LOCK_OPTIONS_MASK)) { __LIBPLATFORM_CLIENT_CRASH__(options, "Invalid options"); } os_ulock_value_t current, new, waiters_mask = 0; ......//删除了第一次加锁不会走到的代码 new = self & ~waiters_mask; bool r = os_atomic_cmpxchgv2o(l, oul_value, OS_LOCK_NO_OWNER, new, ¤t, acquire); if (unlikely(!r)) goto _retry; } void os_unfair_lock_lock(os_unfair_lock_t lock) { _os_unfair_lock_t l = (_os_unfair_lock_t)lock; os_lock_owner_t self = _os_lock_owner_get_self(); bool r = os_atomic_cmpxchg2o(l, oul_value, OS_LOCK_NO_OWNER, self, acquire); if (likely(r)) return; return _os_unfair_lock_lock_slow(l, self, OS_UNFAIR_LOCK_NONE); } static inline os_lock_owner_t _os_lock_owner_get_self(void) { os_lock_owner_t self; self = (os_lock_owner_t)_os_tsd_get_direct(__TSD_MACH_THREAD_SELF); return self; }
先把关注点放在 _os_lock_owner_get_self
函数。
_os_tsd_get_direct
也能找到源码,
static __inline__ void* _os_tsd_get_direct(unsigned long slot) { void *ret; __asm__("mov %%gs:%1, %0" : "=r" (ret) : "m" (*(void **)(slot * sizeof(void *)))); return ret; }
很幸运的是在开源代码 libpthread里发现了下面的代码
void * _pthread_getspecific_direct(unsigned long slot) { #if TARGET_IPHONE_SIMULATOR return pthread_getspecific(slot); #else return _os_tsd_get_direct(slot); #endif }
pthread_getspecific
函数在咱引用 #import <pthread.h>
后是可以调用的。
void * owner = pthread_getspecific(3);
做过实验后发现 owner & ~waiters_mask;
正好等于 _os_unfair_lock_opaque 的值。
现在就找到了os_unfair_lock与线程相关的值。
也可以看一下 os_unfair_lock_assert_owner 函数的源码,该函数是判断当前线程是否是 os_unfair_lock 的所有者,否则触发断言。
“`
- 问题
- 常用的锁
- os_unfair_lock
- 简单介绍
- 追溯锁的拥有者
问题
在iOS开发调试的过程中,有时会发现app卡死了,点击 pause program execution
暂停程序,会发现程序停到等待某个锁上面。如果程序停止在咱自己的代码上面还好排查一点。如果停在没有源码的第三方库或者系统库中,这就不好排查问题了。
这里有一个小方法,可能会提供一点帮助。那就是找到这个锁被那个线程占用了。
常用的锁
iOS中有很多锁,目前比较常用的有 pthread_mutex
、NSLock
、os_unfair_lock
、@synchronized
和dispatch_semaphore
。但不是所有的锁都能找到其被哪个线程所拥有。
目前我知道的能找到其拥有者的锁是 pthread_mutex_t
、os_unfair_lock
以及基于这二者实现的其他上层 API,包括dispatch_once
、NSLock
,NSRecursiveLock
,@synchronized
。
其中dispatch_once
的实现是基于 os_unfair_lock
,剩下的实现是基于pthread_mutex_t
os_unfair_lock
简单介绍
os_unfair_lock
是一个低等级锁, 设计宗旨是用于替换 OSSpinLock
,从 iOS 10
之后开始支持,跟 OSSpinLock
不同,等待 os_unfair_lock
的线程会处于休眠状态.
使用时首先要引入头文件#import
os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;//必须这么初始化 os_unfair_lock_lock(&lock);//加锁 //临界区 os_unfair_lock_unlock(&lock);//解锁
追溯锁的拥有者
os_unfair_lock 是一个结构体
typedef struct os_unfair_lock_s { uint32_t _os_unfair_lock_opaque; } os_unfair_lock, *os_unfair_lock_t;
初始化就是把 _os_unfair_lock_opaque 赋值为零
(lldb) p _lock (os_unfair_lock) $0 = (_os_unfair_lock_opaque = 0)
执行加锁代码后再次查看
(lldb) p _lock (os_unfair_lock) $4 = (_os_unfair_lock_opaque = 4358)
(4358 的十六进制是0x1106)
从google上搜 os_unfair_lock_lock site:opensource.apple.com 能找到开源代码libplatform,我看的是220.100.1
这一版
#ifndef __TSD_MACH_THREAD_SELF #define __TSD_MACH_THREAD_SELF 3 #endif static void _os_unfair_lock_lock_slow(_os_unfair_lock_t l, os_lock_owner_t self, os_unfair_lock_options_t options) { os_unfair_lock_options_t allow_anonymous_owner = options & OS_UNFAIR_LOCK_ALLOW_ANONYMOUS_OWNER; options &= ~OS_UNFAIR_LOCK_ALLOW_ANONYMOUS_OWNER; if (unlikely(options & ~OS_UNFAIR_LOCK_OPTIONS_MASK)) { __LIBPLATFORM_CLIENT_CRASH__(options, "Invalid options"); } os_ulock_value_t current, new, waiters_mask = 0; ......//删除了第一次加锁不会走到的代码 new = self & ~waiters_mask; bool r = os_atomic_cmpxchgv2o(l, oul_value, OS_LOCK_NO_OWNER, new, ¤t, acquire); if (unlikely(!r)) goto _retry; } void os_unfair_lock_lock(os_unfair_lock_t lock) { _os_unfair_lock_t l = (_os_unfair_lock_t)lock; os_lock_owner_t self = _os_lock_owner_get_self(); bool r = os_atomic_cmpxchg2o(l, oul_value, OS_LOCK_NO_OWNER, self, acquire); if (likely(r)) return; return _os_unfair_lock_lock_slow(l, self, OS_UNFAIR_LOCK_NONE); } static inline os_lock_owner_t _os_lock_owner_get_self(void) { os_lock_owner_t self; self = (os_lock_owner_t)_os_tsd_get_direct(__TSD_MACH_THREAD_SELF); return self; }
先把关注点放在 _os_lock_owner_get_self
函数。
_os_tsd_get_direct
也能找到源码,
static __inline__ void* _os_tsd_get_direct(unsigned long slot) { void *ret; __asm__("mov %%gs:%1, %0" : "=r" (ret) : "m" (*(void **)(slot * sizeof(void *)))); return ret; }
很幸运的是在开源代码 libpthread里发现了下面的代码
void * _pthread_getspecific_direct(unsigned long slot) { #if TARGET_IPHONE_SIMULATOR return pthread_getspecific(slot); #else return _os_tsd_get_direct(slot); #endif }
pthread_getspecific
函数在咱引用 #import <pthread.h>
后是可以调用的。
void * owner = pthread_getspecific(3);
做过实验后发现 owner & ~waiters_mask;
正好等于 _os_unfair_lock_opaque 的值。
现在就找到了os_unfair_lock与线程相关的值。
也可以看一下 os_unfair_lock_assert_owner 函数的源码,该函数是判断当前线程是否是 os_unfair_lock 的所有者,否则触发断言。
“`
部分转自互联网,侵权删除联系
最新评论