如何知道一个锁到底被哪个线程占用?

解决思路

对于常用的某几种锁,操作系统会记录其持有线程(owner)是谁的信息。

pthread_mutex 互斥锁

互斥锁的结构为pthread_mutex_s,对应的源码在prototypes_internal.h中定义,如下:

struct pthread_mutex_s {
    long sig;                      //8
    _pthread_lock lock;     //4
    union {
        uint32_t value;
        struct pthread_mutex_options_s options;
    } mtxopts;                   //4
    int16_t prioceiling;     //2
    int16_t priority;           //2
#if defined(__LP64__)
    uint32_t _pad;          //4
#endif
    union {
        struct {
            uint32_t m_tid[2]; // thread id of thread that has mutex locked
            uint32_t m_seq[2]; // mutex sequence id
            uint32_t m_mis[2]; // for misaligned locks m_tid/m_seq will span into here
        } psynch;
        struct _pthread_mutex_ulock_s ulock;
    };
#if defined(__LP64__)
    uint32_t _reserved[4];
#else
    uint32_t _reserved[1];
#endif
};
typedef struct pthread_mutex_s pthread_mutex_t;

其中拥有该锁的线程ID保存在变量m_tid中,相对pthread_mutex_s结构的偏移为24字节,也就是0x18,所以如果知道互斥锁的地址,即可通过地址获取到互斥锁的拥有者线程ID

owner_tid = *(int *)((char *)&mutex + 0x18)

当pthread_mutex 等待锁的时候,会停留在__psynch_mutexwait 函数,对应的锁会放在寄存器x19中,持有该锁的tid获取方法如下

(lldb)  p/x *((int*)($x19 + 0x18))
(int) 0x001f734e

对于NSLock,如果知道对应NSLock的地址,则可以通过NSLock获取到对应的tid,方法如下

(lldb) p/x *((int*)((char*)self->_lock + 0x20))
(int) 0x001f734e

通过thread list打印当前线程列表,可知该锁被thread #7持有

(lldb) thread list
Process 4551 stopped
* thread #1: tid = 0x1f725d, 0x00000001fbe09ca8 libsystem_kernel.dylib`__psynch_mutexwait + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  thread #3: tid = 0x1f734a, 0x000000021e6bb9fc libsystem_pthread.dylib`start_wqthread
  thread #7: tid = 0x1f734e, 0x00000001fbe09978 libsystem_kernel.dylib`__semwait_signal + 8, queue = 'com.apple.root.default-qos'
  thread #8: tid = 0x1f734f, 0x00000001fbe09178 libsystem_kernel.dylib`mach_msg2_trap + 8, name = 'com.apple.uikit.eventfetch-thread'
  thread #9: tid = 0x1f7350, 0x000000021e6bb9fc libsystem_pthread.dylib`start_wqthread
  thread #10: tid = 0x1f7351, 0x000000021e6bb9fc libsystem_pthread.dylib`start_wqthread

_psynch_mutexwait的定义在darwin-libpthreadkern_synch.c 文件,定义如下,tid为mutex的持有线程tid

int _psynch_mutexwait(__unused proc_t p, user_addr_t mutex, uint32_t mgen, uint32_t ugen, uint64_t tid, uint32_t flags, uint32_t *retval)

根据ARM汇编的参数传递,tid保存在x3寄存器,此时寄存器的值还没有被污染,可以直接使用x3来打印持有该锁的tid

(lldb) p/x $x3
(unsigned long) 0x00000000001f734e

_pthread_mutex_firstfit_lock_wait(pthread_mutex_t *mutex, mutex_seq newseq, uint64_t oldtid) 实现在pthread_mutex.c
调用栈如下:

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #0: 0x00000001fbe09ca8 libsystem_kernel.dylib`__psynch_mutexwait + 8
    frame #1: 0x000000021e6bbd68 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_wait + 84
  * frame #2: 0x000000021e6bb7f0 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_slow + 248
    frame #3: 0x00000001009b810c WeTest`-[ViewController viewDidLoad](self=0x0000000101907e10, _cmd="viewDidLoad") at ViewController.m:27:5
    frame #4: 0x00000001b6b61c8c UIKitCore`-[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled] + 84
    frame #5: 0x00000001b6916854 UIKitCore`-[UIViewController loadViewIfRequired] + 936
    frame #6: 0x00000001b6915048 UIKitCore`-[UIViewController view] + 24
    frame #7: 0x00000001b6988084 UIKitCore`-[UIWindow addRootViewControllerViewIfPossible] + 136
    frame #8: 0x00000001b6987f78 UIKitCore`-[UIWindow _updateLayerOrderingAndSetLayerHidden:actionBlock:] + 216
    frame #9: 0x00000001b6987c78 UIKitCore`-[UIWindow _setHidden:forced:] + 256
    frame #10: 0x00000001b6987b04 UIKitCore`-[UIWindow _mainQueue_makeKeyAndVisible] + 40
    frame #11: 0x00000001b6becd5c UIKitCore`-[UIWindowScene _performDeferredInitialWindowUpdateForConnection] + 208
    frame #12: 0x00000001b6a93e14 UIKitCore`+[UIScene _sceneForFBSScene:create:withSession:connectionOptions:] + 1232
    frame #13: 0x00000001b6b50e8c UIKitCore`-[UIApplication _connectUISceneFromFBSScene:transitionContext:] + 808
    frame #14: 0x00000001b6b509b4 UIKitCore`-[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 360
    frame #15: 0x00000001b6b507e0 UIKitCore`-[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 288
    frame #16: 0x00000001ccb696d4 FrontBoardServices`-[FBSScene _callOutQueue_didCreateWithTransitionContext:completion:] + 324
    frame #17: 0x00000001ccb69570 FrontBoardServices`__92-[FBSWorkspaceScenesClient createSceneWithIdentity:parameters:transitionContext:completion:]_block_invoke.108 + 280
    frame #18: 0x00000001ccb6819c FrontBoardServices`-[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 168
    frame #19: 0x00000001ccb73f8c FrontBoardServices`__92-[FBSWorkspaceScenesClient createSceneWithIdentity:parameters:transitionContext:completion:]_block_invoke + 352
    frame #20: 0x000000010174eb34 libdispatch.dylib`_dispatch_client_callout + 20
    frame #21: 0x0000000101752530 libdispatch.dylib`_dispatch_block_invoke_direct + 300
    frame #22: 0x00000001ccb64520 FrontBoardServices`__FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 52
    frame #23: 0x00000001ccb644a0 FrontBoardServices`-[FBSMainRunLoopSerialQueue _targetQueue_performNextIfPossible] + 240
    frame #24: 0x00000001ccb64378 FrontBoardServices`-[FBSMainRunLoopSerialQueue _performNextFromRunLoopSource] + 28
    frame #25: 0x00000001b470d12c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
    frame #26: 0x00000001b470c3a8 CoreFoundation`__CFRunLoopDoSource0 + 176
    frame #27: 0x00000001b470abbc CoreFoundation`__CFRunLoopDoSources0 + 340
    frame #28: 0x00000001b4709898 CoreFoundation`__CFRunLoopRun + 828
    frame #29: 0x00000001b4709478 CoreFoundation`CFRunLoopRunSpecific + 608
    frame #30: 0x00000001f7c624f8 GraphicsServices`GSEventRunModal + 164
    frame #31: 0x00000001b6b2d62c UIKitCore`-[UIApplication _run] + 888
    frame #32: 0x00000001b6b2cc68 UIKitCore`UIApplicationMain + 340
    frame #33: 0x00000001009b85d4 WeTest`main(argc=1, argv=0x000000016f44b7d8) at main.m:17:12
    frame #34: 0x00000001d742edcc dyld`start + 2240

NSLock

对于NSLock 类型对象 lock:

  1. 对应的pthread_mutex_t的地址为&lock + 0x8
  2. 对应的tid地址为&lock + 0x20,

案例分析

堆栈

image.png
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x00000001e8471ca8 libsystem_kernel.dylib`__psynch_mutexwait + 8
    frame #1: 0x000000020ad23d68 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_wait + 84
    frame #2: 0x000000020ad237f0 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_slow + 248
    frame #3: 0x00000001007312e0 QQKSong`-[HippyExtAnimationModule animationDidStop:finished:](self=0x000000028168bb40, _cmd=<unavailable>, anim=<unavailable>, flag=<unavailable>) at HippyExtAnimationModule.m:308:5 [opt]
    frame #4: 0x00000001a238b67c QuartzCore`-[CALayer addAnimation:forKey:] + 512
    frame #5: 0x0000000100732098 QQKSong`__50-[HippyExtAnimationModule connectAnimationToView:]_block_invoke_2(.block_descriptor=<unavailable>, ani=<unavailable>, idx=<unavailable>, stop=<unavailable>) at HippyExtAnimationModule.m:419:9 [opt]
    frame #6: 0x00000001a0d733f4 CoreFoundation`__NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__ + 24
    frame #7: 0x00000001a0d73120 CoreFoundation`-[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 320
    frame #8: 0x0000000100731e5c QQKSong`-[HippyExtAnimationModule connectAnimationToView:](self=0x000000028168bb40, _cmd=<unavailable>, view=<unavailable>) at HippyExtAnimationModule.m:417:5 [opt]
    frame #9: 0x0000000100730638 QQKSong`__47-[HippyExtAnimationModule paramForAnimationId:]_block_invoke_3(.block_descriptor=<unavailable>, tag=<unavailable>, idx=<unavailable>, stop=<unavailable>) at HippyExtAnimationModule.m:228:17 [opt]
    frame #10: 0x00000001a0d733f4 CoreFoundation`__NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__ + 24
    frame #11: 0x00000001a0d73120 CoreFoundation`-[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 320
    frame #12: 0x0000000100730510 QQKSong`__47-[HippyExtAnimationModule paramForAnimationId:]_block_invoke_2(.block_descriptor=0x0000000282332990) at HippyExtAnimationModule.m:221:9 [opt]
    frame #13: 0x00000001a8d2f6a8 libdispatch.dylib`_dispatch_call_block_and_release + 32
    frame #14: 0x00000001a8d31300 libdispatch.dylib`_dispatch_client_callout + 20
    frame #15: 0x00000001a8d3f998 libdispatch.dylib`_dispatch_main_queue_drain + 984
    frame #16: 0x00000001a8d3f5b0 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 44
    frame #17: 0x00000001a0d7501c CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16
    frame #18: 0x00000001a0d71d28 CoreFoundation`__CFRunLoopRun + 1996
    frame #19: 0x00000001a0d71478 CoreFoundation`CFRunLoopRunSpecific + 608
    frame #20: 0x00000001e42ca4f8 GraphicsServices`GSEventRunModal + 164
    frame #21: 0x00000001a319562c UIKitCore`-[UIApplication _run] + 888
    frame #22: 0x00000001a3194c68 UIKitCore`UIApplicationMain + 340
    frame #23: 0x0000000102a8ebb4 QQKSong`UIApplicationMain_wsl(argc=1, argv=0x000000016f8e7788, principalClassName="KSApplication", delegateClassName="KSAppDelegate") at WSGlobalTaskMgr.mm:881:12
    frame #24: 0x000000010053a958 QQKSong`main(argc=1, argv=0x000000016f8e7788) at main.m:40:16
    frame #25: 0x00000001c3a96dcc dyld`start + 2240

获取 owner_tid

(lldb)  p/x *((int*)($x19 + 0x18))
(int) 0x000c342d

获取线程列表,拥有锁的线程ID为0x000c342d为当前线程,应为同一个线程多次lock 一个非递归锁

(lldb) thread list
Process 1790 stopped
* thread #1: tid = 0xc342d, 0x00000001e8471ca8 libsystem_kernel.dylib`__psynch_mutexwait + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  thread #2: tid = 0xc362b, 0x00000001e847ef38 libsystem_kernel.dylib`kevent64 + 8, name = 'im_logic_thread'
  thread #5: tid = 0xc3630, 0x00000001e8471b1c libsystem_kernel.dylib`__psynch_cvwait + 8
  thread #6: tid = 0xc3631, 0x00000001e8471b1c libsystem_kernel.dylib`__psynch_cvwait + 8
  thread #7: tid = 0xc3632, 0x00000001e8471b1c libsystem_kernel.dylib`__psynch_cvwait + 8
.....

查看代码

@implementation HippyExtAnimationModule {
    NSMutableDictionary<NSNumber *, HippyExtAnimation *> *_animationById;
    NSMutableDictionary<NSNumber *, NSMutableArray<HippyExtAnimationViewParams *> *> *_paramsByAnimationId;
    NSMutableDictionary<NSNumber *, HippyExtAnimationViewParams *> *_paramsByHippyTag;
    NSLock *_lock;
    HippyExtAnimationIdCount *_virtualAnimations;
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    [_lock lock];
    NSNumber *animationId = [anim valueForKey:@"animationID"];
    NSNumber *viewId = [anim valueForKey:@"viewID"];

    NSMutableArray<HippyExtAnimationViewParams *> *params = [_paramsByAnimationId[animationId] copy];
    [self.bridge.uiManager executeBlockOnUIManagerQueue:^{
        [params enumerateObjectsUsingBlock:^(HippyExtAnimationViewParams *p, __unused NSUInteger idx, __unused BOOL *stop) {
            [p.animationIdWithPropDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSNumber *obj, __unused BOOL *stop1) {
                HippyExtAnimation *ani = self->_animationById[obj];
                if (![obj isEqual:animationId]) {
                    return;
                }

                [p setValue:@(ani.endValue) forProp:key];
                ani.state = HippyExtAnimationFinishState;
                HippyLogInfo(@"[Hippy_OC_Log][Animation],Animation_Did_Stop:%@ finish:%@ prop:%@ value:%@", animationId, @(flag), key, @(ani.endValue));
            }];
        }];
    }];
    [_lock unlock];
 //其它代码
}

根据NSLock锁验证前面的线程ID获取正确

(lldb) p/x *((int*)((char*)self->_lock + 0x20))
(int) 0x000c342d

递归原因:

  1. connectAnimationToView里面加锁
  2. 在animationDidStop里面尝试再次加锁
- (void)connectAnimationToView:(UIView *)view {
    [_lock lock];
    NSNumber *hippyTag = view.hippyTag;
    HippyExtAnimationViewParams *p = _paramsByHippyTag[hippyTag];

    NSMutableArray<CAAnimation *> *animations = [NSMutableArray new];
    [p.animationIdWithPropDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *prop, NSNumber *animationId, __unused BOOL *stop) {
        HippyExtAnimation *animation = self->_animationById[animationId];
        if (animation.state != HippyExtAnimationReadyState) {
            return;
        }
        CAAnimation *ani = [animation animationOfView:view forProp:prop];
        animation.state = HippyExtAnimationStartedState;
        [ani setValue:animationId forKey:@"animationID"];
        if (animation.parentAnimationId) {
            [ani setValue:animation.parentAnimationId forKey:@"animationParentID"];
        }
        [ani setValue:view.hippyTag forKey:@"viewID"];
        ani.delegate = self;
        [animations addObject:ani];
        HippyLogInfo(@"[Hippy_OC_Log][Animation],Connect_Animation:[%@] to view [%@] prop [%@] from [%@] to [%@]", animationId, view.hippyTag, prop, @(animation.startValue),
                     @(animation.endValue));

    }];
    [animations enumerateObjectsUsingBlock:^(CAAnimation *_Nonnull ani, __unused NSUInteger idx, __unused BOOL *stop) {
        NSNumber *animationId = [ani valueForKey:@"animationID"];
        [view.layer addAnimation:ani forKey:[NSString stringWithFormat:@"%@", animationId]];
    }];

    [_lock unlock];
}

各函数所在模块

如下堆栈可知

 * frame #0: 0x00000001d358dca0 libsystem_kernel.dylib`__psynch_mutexwait
    frame #1: 0x00000001f5e3fd68 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_wait + 84
    frame #2: 0x00000001f5e3f7f0 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_slow + 248
    frame #3: 0x000000019c089d20 libc++.1.dylib`std::__1::mutex::lock() + 16
    frame #4: 0x00000001121606bc ImSDK_Plus`___lldb_unnamed_symbol1953 + 117764
    frame #5: 0x0000000112160ec8 ImSDK_Plus`___lldb_unnamed_symbol1953 + 119824
    frame #6: 0x00000001f5e404d4 libsystem_pthread.dylib`_pthread_start + 136

相关模块的源码链接

参考文献

  1. 如何知道一个锁到底被哪个线程占用?
  2. ARMv8-aarch64 寄存器和指令集
  3. libsystem_pthread源码: darwin-libpthread

源码

_pthread_mutex_firstfit_lock_wait

static int
_pthread_mutex_firstfit_lock_wait(pthread_mutex_t *mutex, mutex_seq newseq,
        uint64_t oldtid)
{
    uint64_t *tidaddr;
    MUTEX_GETTID_ADDR(mutex, &tidaddr);
    uint64_t selfid = _pthread_threadid_self_np_direct();

    PLOCKSTAT_MUTEX_BLOCK((pthread_mutex_t *)mutex);
    do {
        uint32_t uval;
        do {
            PTHREAD_TRACE(psynch_ffmutex_wait | DBG_FUNC_START, mutex,
                    newseq.lgenval, newseq.ugenval, mutex->mtxopts.value);
            uval = __psynch_mutexwait(mutex, newseq.lgenval, newseq.ugenval,
                    oldtid, mutex->mtxopts.value);
            PTHREAD_TRACE(psynch_ffmutex_wait | DBG_FUNC_END, mutex,
                    uval, 0, 0);
            oldtid = os_atomic_load_wide(tidaddr, relaxed);
        } while (uval == (uint32_t)-1);
    } while (!_pthread_mutex_firstfit_lock_updatebits(mutex, selfid, &newseq));
    PLOCKSTAT_MUTEX_BLOCKED((pthread_mutex_t *)mutex, BLOCK_SUCCESS_PLOCKSTAT);

    return 0;
}

对应汇编如下
第一个参数为pthread_mutex_t,对应的寄存器为x0,在此过程中,把x0保存到寄存器x19,而在后续过程中没有使用它,所以在x19中保存着pthread_mutex_t对象的指针
寄存器X19X29是被调用者保存寄存器,也称为Callee-saved寄存器。如果在函数中使用这些寄存器,你必须在函数入口处将它们推入栈中(保存它们的状态),并在函数退出之前从栈中恢复它们。

libsystem_pthread.dylib`:
    0x1f5e3fd14 <+0>:   pacibsp 
    0x1f5e3fd18 <+4>:   stp    x24, x23, [sp, #-0x40]!
    0x1f5e3fd1c <+8>:   stp    x22, x21, [sp, #0x10]
    0x1f5e3fd20 <+12>:  stp    x20, x19, [sp, #0x20]
    0x1f5e3fd24 <+16>:  stp    x29, x30, [sp, #0x30]
    0x1f5e3fd28 <+20>:  add    x29, sp, #0x30
    0x1f5e3fd2c <+24>:  mov    x3, x2
    0x1f5e3fd30 <+28>:  mov    x19, x0
    0x1f5e3fd34 <+32>:  add    x8, x0, #0x1f
    0x1f5e3fd38 <+36>:  and    x22, x8, #0xfffffffffffffff8
    0x1f5e3fd3c <+40>:  mrs    x8, TPIDRRO_EL0
    0x1f5e3fd40 <+44>:  ldur   x23, [x8, #-0x8]
    0x1f5e3fd44 <+48>:  add    x8, x0, #0x27
    0x1f5e3fd48 <+52>:  and    x24, x8, #0xfffffffffffffff8
    0x1f5e3fd4c <+56>:  mov    x20, x1
    0x1f5e3fd50 <+60>:  lsr    x21, x1, #32
    0x1f5e3fd54 <+64>:  ldr    w4, [x19, #0xc]
    0x1f5e3fd58 <+68>:  mov    x0, x19
    0x1f5e3fd5c <+72>:  mov    x1, x20
    0x1f5e3fd60 <+76>:  mov    x2, x21
    0x1f5e3fd64 <+80>:  bl     0x1f67e95b0
->  0x1f5e3fd68 <+84>:  ldr    x3, [x22]
    0x1f5e3fd6c <+88>:  cmn    w0, #0x1
    0x1f5e3fd70 <+92>:  b.eq   0x1f5e3fd54               ; <+64>
    0x1f5e3fd74 <+96>:  ldr    x8, [x24]
    0x1f5e3fd78 <+100>: mov    x1, x8
    0x1f5e3fd7c <+104>: add    w9, w1, #0x100
    0x1f5e3fd80 <+108>: orr    w10, w1, #0x2
    0x1f5e3fd84 <+112>: tst    x8, #0x2
    0x1f5e3fd88 <+116>: csel   x9, x10, x9, eq
    0x1f5e3fd8c <+120>: mov    x20, x8
    0x1f5e3fd90 <+124>: bfxil  x20, x9, #0, #32
    0x1f5e3fd94 <+128>: casa   x8, x20, [x24]
    0x1f5e3fd98 <+132>: cmp    x8, x1
    0x1f5e3fd9c <+136>: b.ne   0x1f5e3fd78               ; <+100>
    0x1f5e3fda0 <+140>: tbnz   w1, #0x1, 0x1f5e3fd50     ; <+60>
    0x1f5e3fda4 <+144>: str    x23, [x22]
    0x1f5e3fda8 <+148>: ldp    x29, x30, [sp, #0x30]
    0x1f5e3fdac <+152>: ldp    x20, x19, [sp, #0x20]
    0x1f5e3fdb0 <+156>: ldp    x22, x21, [sp, #0x10]
    0x1f5e3fdb4 <+160>: ldp    x24, x23, [sp], #0x40
    0x1f5e3fdb8 <+164>: retab  

__psynch_mutexwait 汇编

libsystem_kernel.dylib`:
->  0x1d358dca0 <+0>:  mov    x16, #0x12d
    0x1d358dca4 <+4>:  svc    #0x80
    0x1d358dca8 <+8>:  b.lo   0x1d358dcc8               ; <+40>
    0x1d358dcac <+12>: pacibsp 
    0x1d358dcb0 <+16>: stp    x29, x30, [sp, #-0x10]!
    0x1d358dcb4 <+20>: mov    x29, sp
    0x1d358dcb8 <+24>: bl     0x1d358d76c               ; cerror_nocancel
    0x1d358dcbc <+28>: mov    sp, x29
    0x1d358dcc0 <+32>: ldp    x29, x30, [sp], #0x10
    0x1d358dcc4 <+36>: retab  
    0x1d358dcc8 <+40>: ret    

(lldb) p/x $x19
(unsigned long) 0x000000028153f700
(lldb) p/x $x0
(unsigned long) 0x000000028153f700

互斥锁对应的结构为pthread_mutex_t,如下

typedef struct _pthread_mutex
{
    long           sig;       /* Unique signature for this structure */
    pthread_lock_t lock;          /* Used for internal mutex on structure */
    union {
        uint32_t value;
        struct _pthread_mutex_options options;
    } mtxopts;
    int16_t       prioceiling;
    int16_t        priority;      /* Priority to restore when mutex unlocked */
    uint32_t      waiters;       /* Count of threads waiting for this mutex */
    pthread_t      owner;         /* Which thread has this mutex locked */
    struct _pthread_mutex *next, *prev;  /* List of other mutexes he owns */
    struct _pthread_cond *busy;   /* List of condition variables using this mutex */
    semaphore_t    sem;       /* Semaphore used for waiting */
    semaphore_t order;
} pthread_mutex_t;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容