iOS 十种线程锁

作者: 有毒的程序猿 | 来源:发表于2017-11-11 19:46 被阅读279次

前言

我觉得打游戏屏蔽脏话挺有必要的, 我走中单, 打野一直拿我蓝, 我开大打他路过交惩戒抢, 我气的不行, 就骂他, 结果打出来的都是"李白你是不是 * * * ?"、"抢 * * *的蓝", 我觉得没气势, 没办法, 我打了个"李白你个大坏蛋", 他就再也没抢过了, 还掩护我打蓝.

iOS 十种线程锁.jpeg

锁 是什么意思?

  • 我们在使用多线程的时候多个线程可能会访问同一块资源,这样就很容易引发数据错乱和数据安全等问题,这时候就需要我们保证每次只有一个线程访问这一块资源,锁 应运而生。
  • 这里顺便提一下,上锁的两种方式trylock和lock使用场景:
当前线程锁失败,也可以继续其它任务,用 trylock 合适
当前线程只有锁成功后,才会做一些有意义的工作,那就 lock,没必要轮询 trylock
注:以下大部分锁都会提供trylock接口,不再作解释
感谢yy大神.png

<准备操作>

测试代码
#define RHTICK   NSDate *startTime = [NSDate date];
#define RHTOCK   NSLog(@"==========Time: %f", -[startTime timeIntervalSinceNow]);
NSUInteger count = 1000*10000;//执行一千万次
RHTICK
for(int i=0; i<count; i++) {
加锁
解锁
}
RHTOCK
注:测试中执行时间会波动,所以我取的平均值.

一、OSSpinLock (自旋锁)

测试中效率最高的锁, 不过经YYKit作者确认, OSSpinLock已经不再线程安全,OSSpinLock有潜在的优先级反转问题.不再安全的 OSSpinLock;

  • 0.097348s
需要导入头文件
#import <libkern/OSAtomic.h>
// 初始化
 OSSpinLock spinLock = OS_SPINLOCK_INIT;
// 加锁
OSSpinLockLock(&spinLock);
// 解锁
OSSpinLockUnlock(&spinLock);
// 尝试加锁,可以加锁则立即加锁并返回 YES,反之返回 NO
OSSpinLockTry(&spinLock)
/*
注:苹果爸爸已经在iOS10.0以后废弃了这种锁机制,使用os_unfair_lock 替换,
顾名思义能够保证不同优先级的线程申请锁的时候不会发生优先级反转问题.
*/

二、os_unfair_lock(自旋锁)

  • 0.171789s
需要导入头文件
#import <os/lock.h>
// 初始化
 os_unfair_lock unfair_lock = OS_UNFAIR_LOCK_INIT;
// 加锁
os_unfair_lock_lock(&unfair_lock);
// 解锁
os_unfair_lock_unlock(&unfair_lock);
// 尝试加锁,可以加锁则立即加锁并返回 YES,反之返回 NO
os_unfair_lock_trylock(&unfair_lock);
/*
注:解决不同优先级的线程申请锁的时候不会发生优先级反转问题.
不过相对于 OSSpinLock , os_unfair_lock性能方面减弱了许多.
*/

三、dispatch_semaphore (信号量)

  • 0.155043s
// 初始化
dispatch_semaphore_t semaphore_t = dispatch_semaphore_create(1);
// 加锁
dispatch_semaphore_wait(semaphore_t,DISPATCH_TIME_FOREVER);
// 解锁
dispatch_semaphore_signal(semaphore_t);
/*
注: dispatch_semaphore  其他两个功能
1.还可以起到阻塞线程的作用.
2.可以实现定时器功能,这里不做过多介绍.
*/

四、pthread_mutex(互斥锁)

  • 0.262592s
需要导入头文件
#import <pthread/pthread.h>
// 初始化(两种)
1.普通初始化
pthread_mutex_t mutex_t;
pthread_mutex_init(&mutex_t, NULL); 
2.宏初始化
pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;
// 加锁
pthread_mutex_lock(&mutex_t);
// 解锁
pthread_mutex_unlock(&mutex_t);
// 尝试加锁,可以加锁时返回的是 0,否则返回一个错误
pthread_mutex_trylock(& mutex_t)

五、NSLock(互斥锁、对象锁)

  • 0.283196s
// 初始化
NSLock *_lock = [[NSLock alloc]init];
// 加锁
[_lock lock];
// 解锁
[_lock unlock];
// 尝试加锁,可以加锁则立即加锁并返回 YES,反之返回 NO
[_lock tryLock];

六、NSCondition(条件锁、对象锁)

  • 0.293046s
// 初始化
NSCondition *_condition= [[NSCondition alloc]init];
// 加锁
[_condition lock];
// 解锁
[_condition unlock];
/*
其他功能接口
wait 进入等待状态
waitUntilDate:让一个线程等待一定的时间
signal 唤醒一个等待的线程
broadcast 唤醒所有等待的线程
注: 所测时间波动太大, 有时候会快于 NSLock, 我取得中间值.
*/

七、NSConditionLock(条件锁、对象锁)

  • 0.950285s
// 初始化
NSConditionLock *_conditionLock = [[NSConditionLock alloc]init];
// 加锁
[_conditionLock lock];
// 解锁
[_conditionLock unlock];
// 尝试加锁,可以加锁则立即加锁并返回 YES,反之返回 NO
[_conditionLock tryLock];
/*
其他功能接口
- (instancetype)initWithCondition:(NSInteger)condition NS_DESIGNATED_INITIALIZER; //初始化传入条件
- (void)lockWhenCondition:(NSInteger)condition;//条件成立触发锁
- (BOOL)tryLockWhenCondition:(NSInteger)condition;//尝试条件成立触发锁
- (void)unlockWithCondition:(NSInteger)condition;//条件成立解锁
- (BOOL)lockBeforeDate:(NSDate *)limit;//触发锁 在等待时间之内
- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;//触发锁 条件成立 并且在等待时间之内
*/

八、NSRecursiveLock(递归锁、对象锁)

  • 0.473536s
// 初始化
NSRecursiveLock *_recursiveLock = [[NSRecursiveLock alloc]init];
// 加锁
[_recursiveLock lock];
// 解锁
[_recursiveLock unlock];
// 尝试加锁,可以加锁则立即加锁并返回 YES,反之返回 NO
[_recursiveLock tryLock];
/*
注: 递归锁可以被同一线程多次请求,而不会引起死锁。
即在同一线程中在未解锁之前还可以上锁, 执行锁中的代码。
这主要是用在循环或递归操作中。
- (BOOL)lockBeforeDate:(NSDate *)limit;//触发锁 在等待时间之内
*/

九、@synchronized(条件锁)

  • 1.101924s
// 初始化
@synchronized(条件){
}

更多关于@synchronized;

十、pthread_mutex(recursive)(递归锁)

  • 0.372398s
// 初始化
pthread_mutex_t mutex_t;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr); //初始化attr并且给它赋予默认pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); //设置锁类型,这边是设置为递归锁
pthread_mutex_init(&mutex_t, &attr);
pthread_mutexattr_destroy(&attr); //销毁一个属性对象,在重新进行初始化之前该结构不能重新使用
// 加锁
pthread_mutex_lock(&mutex_t);
// 解锁
pthread_mutex_unlock(&mutex_t);
/*
注: 递归锁可以被同一线程多次请求,而不会引起死锁。
即在同一线程中在未解锁之前还可以上锁, 执行锁中的代码。
这主要是用在循环或递归操作中。
*/

性能总结

OSSpinLock                          0.097348s
dispatch_semaphore                  0.155043s
os_unfair_lock                      0.171789s
pthread_mutex                       0.262592s
NSLock                              0.283196s
pthread_mutex(recursive)            0.372398s
NSRecursiveLock                     0.473536s
NSConditionLock                     0.950285s
@synchronized                       1.101924s
注:建议正常锁功能用 pthread_mutex ,os_unfair_lock (适配低版本)

相关文章

  • iOS 十种线程锁

    iOS 十种线程锁

  • 起底多线程同步锁(iOS)

    起底多线程同步锁(iOS) 起底多线程同步锁(iOS)

  • iOS 十种线程锁

    前言 我觉得打游戏屏蔽脏话挺有必要的, 我走中单, 打野一直拿我蓝, 我开大打他路过交惩戒抢, 我气的不行, 就骂...

  • iOS 十种线程锁

    锁 是什么意思? 我们在使用多线程的时候多个线程可能会访问同一块资源,这样就很容易引发数据错乱和数据安全等问题,这...

  • OC--各种线程锁

    参考:正确使用多线程同步锁@synchronized()iOS中的锁iOS多线程安全详解iOS 常见知识点(三):...

  • 多线程 (三)iOS中的锁

    ios 多线程--锁

  • iOS的线程安全与锁

    iOS的线程安全与锁

  • 线程锁

    iOS中有几种线程锁:@synchronized、NSLock以及NSRecursiveLock(递归锁)。本文用...

  • GCD练习

    GCD练习 ios 多线程 GCD : ios 多线程 全剧队列,异步执行 线程间通信 信号量 文件锁 单利模式 ...

  • iOS线程锁的研究

    iOS线程锁的研究 在开始说线程锁之前,我们需要了解线程的概念。 什么是线程 线程,有时被称为轻量级进程(LWP)...

网友评论

本文标题:iOS 十种线程锁

本文链接:https://www.haomeiwen.com/subject/kuawmxtx.html