iOS同步锁

1 性能对比

2 介绍与使用

2.1 OSSpinLock

OSSpinLock 目前已不再安全,主要原因发生在低优先级线程拿到锁时,高优先级线程进入忙等(busy-wait)状态,消耗大量 CPU 时间,从而导致低优先级线程拿不到 CPU 时间,也就无法完成任务并释放锁。这种问题被称为优先级反转。

OSSpinLock theLock = OS_SPINLOCK_INIT;
OSSpinLockLock(&theLock);
OSSpinLockUnlock(&theLock);

2.2 dispatch_semaphore

dispatch_semaphore 是 GCD 用来同步的一种方式。允许通过 wait/signal 的信号事件控制并发执行的最大线程数,当最大线程数降级为1的时候则可当作同步锁使用。注意该信号量并不支持递归

dispatch_semaphore_t signal = dispatch_semaphore_create(1);
dispatch_semaphore_wait(signal, overTime);
dispatch_semaphore_signal(signal);

2.3 pthread_mutex

POSIX标准的unix多线程库(pthread)中使用的互斥量,支持 while 循环。

pthread_mutex_t lock
pthread_mutex_init(&lock, NULL);
pthread_mutex_lock(&lock);加锁
pthread_mutex_tylock(&lock); / pthread_mutex_trylock(&lock) == 0
pthread_mutex_unlock(&lock);
pthread_mutex_destroy(&lock);

2.4 NSLock

典型的面向对象的锁,即同步锁类。所有锁(包括NSLock)遵循 Objective-C 的 NSLocking 协议接口,支持 tryLock 和 lockBeforeDate: 。底层通过 pthread_mutex 实现。

NSLock *lock = [[NSLock alloc] init];

if ([lock tryLock]) { // 尝试加锁,如果失败返回NO,不会阻塞该线程
    [lock unlock];
}
if ([lock lockBeforeDate:date]) { // 在Date之前尝试加锁,如果不能加锁,则返回NO
    [lock unlock];
}

2.5 NSCondition

NSCondition基于信号量方式实现的锁对象,提供单独的信号量管理接口。底层通过pthread_cond_t实现。

NSCondition *condition = [[NSCondition alloc] init];
[condition lock];
[condition wait];   // 让当前线程处于等待状态
[condition signal]; // CPU发信号告诉线程不用在等待,可以继续执行
[condition unlock];

2.6 pthread_mutex(recursive)

pthread_mutex的递归锁实现,作用和NSRecursiveLock类似,主要为了防止在递归的情况下出现死锁。

pthread_mutex_t lock;

pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&lock, &attr);
pthread_mutexattr_destroy(&attr);

pthread_mutex_lock(&lock);
pthread_mutex_unlock(&lock);

pthread_mutex_destroy(&lock);

2.7 NSRecursiveLock递归锁

NSRecursiveLock 和 NSLock 一样是面向对象的锁,但是支持递归,不支持tryLock。这个锁可以被同一线程多次请求,而不会引起死锁。这主要是用在循环或递归操作中。

NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init];

void RecursiveFunction(int value) {
    [theLock lock];
    if (value != 0) {
        --value;
        RecursiveFunction(value);
    }
    [theLock unlock];
}

RecursiveFunction(5);

2.8 NSConditionLock条件锁

NSConditionLock 可以使用特定值来加锁和解锁。相比NSCondition更为直接和实用。

id condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA];
while(true) {
    [condLock lock];
    /* Add data to the queue. */
    [condLock unlockWithCondition:HAS_DATA];
}

2.9 @synchronized

通过 @synchronized 可以非常方便的创建一个互斥锁非常方便的方法。@synchronized 通过对象的哈希表来实现。

- (void)myMethod:(id)anObj {
    @synchronized(anObj) {

    }
}

3 结论

  1. 常规和 while 循环加锁使用 pthread_mutex。
  2. 队列(dispatch_get_global_queue)并发线程数控制,使用 dispatch_semaphore。
  3. 递归调用时使用 NSRecursiveLock(项目中不建议使用此方案,风险高)。
  4. 性能要求极度苛刻时,考虑使用 OSSpinLock,不过需要确保加锁片段的耗时足够小。
  5. 不建议使用 NSLock、pthread_mutex(recursive)、NSCondition、NSConditionLock 和 @synchronized。

其实除了上面9种锁,我们还可以通过串行队列实现同步锁。不过那种感觉就像拿着火炮打蚊子,打的准不准不说,其打的速度堪忧。

 


Appendix

不再安全的 OSSpinLock

深入理解 iOS 开发中的锁

起底多线程同步锁(iOS)

[iOS] 正确使用多线程同步锁 @synchronized()

Revision History

时间描述
2017-03-16博文完成

CSDN:http://blog.csdn.net/y550918116j

GitHub:https://github.com/937447974

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值