iOS - 多线程的锁

多线程同时访问同一块资源会造成资源抢夺,容易引发数据错乱和数据安全问题,此时我们需要保证资源同时只有一个线程访问,加锁就是为了解决这个问题。

常用的加锁方式:(性能由差到好)

  • OSSpinLock 自旋锁,存在优先级反转问题,破坏了 spinLock,后来Apple推出 os_unfair_lock_t 解决优先级翻转问题
  • dispatch_semaphore 信号量
  • pthread_mutex 互斥锁 (C语言)
  • NSLock 对象锁
  • NSCondition 条件锁
  • NSRecursiveLock 递归锁
  • NSConditionLock 条件锁
  • @synchronized 性能最差

各种锁的性能比较

自旋锁

‘OSSpinLock’、‘os_unfair_lock’

‘OSSpinLock’ 是一种自旋锁,和互斥锁类似,都是为了保证线程安全的锁。对于互斥锁,当一个线程获得这个锁以后,其他想要获得此锁的线程将会被阻塞,直到该锁被释放;自旋锁,当一个线程获得锁之后,其他线程将会一直循环查看该锁是否被释放,此锁适用于锁的持有者保存时间较短的情况。

spinLock = OS_SPINLOCK_INIT;
OSSpinLockLock(&spinLock);
sleep(4);
OSSpinLockUnlock(&spinLock);

‘OSSpinLock’ 不再安全了? 因为存在优先级翻转的问题。
在新版本iOS系统中,系统维护了5个不同的线程优先级(Qos): background, utility, default, user-initiated, user-interactive。高优先级线程始终会在低优先级线程前执行,一个线程不会受到比他更低优先级线程的干扰。这种线程调度算法会产生潜在的优先级翻转的问题,从而破坏 spin lock.

实例:如果一个低优先级的线程获得锁并访问共享资源,此时一个高优先级的线程也尝试获得这个锁,它会处于 spin lock 的忙时状态从而占用大量CPU,此时低优先级线程无法与高优先级线程抢夺CPU时间,从而导致任务迟迟无法完成,无法释放lock。

为解决此问题,在iOS10,给出了新API:os_unfair_lock

os_unfair_lock_t unfairLock = &(OS_UNFAIR_LOCK_INIT);
os_unfair_lock_lock(unfairLock);
sleep(4);
os_unfair_lock_unlock(unfairLock);

信号量

dispatch_semaphore

信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量

dispatch_semaphore 可以通过控制并发数实现锁机制。通过控制信号量的值为 0 或 1 来实现锁。dispatch_semaphore_wait 会使信号量-1,dispatch_semaphore_signal 会使信号量+1,信号量为0时线程等待,为1时方可继续执行。

#import "Dispatch_Semaphore.h"
@interface Dispatch_Semaphore ()
{dispatch_semaphore_t _semaphore;
}
@property (nonatomic, strong) NSMutableArray *array;
@property (assign) NSUInteger index;
@end
@implementation Dispatch_Semaphore
- (instancetype)init {self = [super init];if (self) {/// 通道默认为1, 首次执行_semaphore = dispatch_semaphore_create(1);}return self;
}
- (void)run {for (NSUInteger i = 0; i < self.array.count; i++) {if (i % 2 == 0) {dispatch_async(dispatch_get_global_queue(0, 0), ^{[self log];});} else {dispatch_async(dispatch_get_global_queue(0, 0), ^{[self log];});}}
}
- (void)log {/// 通道 -1 阻塞其他线程进入dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);NSLog(@"%@",self.array[self.index++]);/// 通道+1 其他线程可进入dispatch_semaphore_signal(_semaphore);
}
- (NSMutableArray *)array {if(!_array){NSMutableArray *arrayM = [NSMutableArray array];for (NSUInteger i = 0; i < 1000; i++) {[arrayM addObject:@(i)];}_array = arrayM;}return _array;
}
@end

互斥锁

pthread_mutex

#import "Phread_mutex.h"
#import <pthread.h>
@interface Phread_mutex ()
{pthread_mutex_t _mutex_t;
}
@property (nonatomic, strong) NSMutableArray *array;
@property (assign) NSUInteger index;
@end@implementation Phread_mutex
- (instancetype)init {self = [super init];if (self) {/// 锁初始化pthread_mutex_t mutex_t = PTHREAD_MUTEX_INITIALIZER;_mutex_t = mutex_t;}return self;
}
- (void)run {for (NSUInteger i = 0; i < self.array.count; i++) {if (i % 2 == 0) {dispatch_async(dispatch_get_global_queue(0, 0), ^{[self log];});} else {dispatch_async(dispatch_get_global_queue(0, 0), ^{[self log];});}}
}
- (void)log {// 加互斥锁pthread_mutex_lock(&(_mutex_t));NSLog(@"%@",self.array[self.index++]);// 解互斥锁pthread_mutex_unlock(&(_mutex_t));
}
- (NSMutableArray *)array {if(!_array){NSMutableArray *arrayM = [NSMutableArray array];for (NSUInteger i = 0; i < 1000; i++) {[arrayM addObject:@(i)];}_array = arrayM;}return _array;
}
@end

NSLock

NSLockNSRecursiveLock, NSConditionLock 都是对 pthread_mutex 的封装。

NSLock 遵循 NSLocking 协议. lock 加锁,unlock 解锁,tryLock 尝试加锁,如果失败的话返回 NO,lockBeforeDate: 是在指定Date之前尝试加锁,如果在指定时间之前都不能加锁,则返回NO。

NSLocking 协议

@protocol NSLocking- (void)lock;
- (void)unlock;@end
- (void)log {// 加互斥锁[self.lock lock];NSLog(@"%@",self.array[self.index++]);// 解互斥锁[self.lock unlock];
}

条件锁

NSConditionLock

NSConditionLock 同样遵循了NSLocking 协议,除此之外,还可以设置自定义条件来获得锁和释放锁.

#import "NSConditionLockDemo.h"
@interface NSConditionLockDemo ()
@property (nonatomic, strong) NSMutableArray *images;
@property (assign) NSUInteger index;
@property (nonatomic, strong) NSConditionLock *conditionLock;
@end
@implementation NSConditionLockDemo
static const NSInteger lockTag = 10086;
static const NSInteger imageCount = 100;
- (instancetype)init {self = [super init];if (self) {self.conditionLock = [[NSConditionLock alloc] init];}return self;
}
- (void)run {for (NSUInteger i = 0; i < imageCount; i++) {dispatch_async(dispatch_get_global_queue(0, 0), ^{[self downloadImages];});}[self showImages];
}
/// 异步下载 imageCount 张图片
- (void)downloadImages {sleep(arc4random_uniform(5));[self.conditionLock lock];[self.images addObject:@(arc4random_uniform(100))];[self.conditionLock unlock];if (self.images.count == imageCount) {[self.conditionLock unlockWithCondition:lockTag];}
}
/// 展示下载好的 imageCount 张图片
- (void)showImages {[self.conditionLock lockWhenCondition:lockTag];[self.images enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {NSLog(@"show: %@",obj);}];[self.conditionLock unlockWithCondition:lockTag];
}
- (NSMutableArray *)images {if(!_images){_images = [NSMutableArray array];}return _images;
}
@end

递归锁

NSRecursiveLock

@interface NSRecursiveLockDemo ()
@property (nonatomic, strong) NSRecursiveLock *recursiveLock;
@end@implementation NSRecursiveLockDemo
- (instancetype)init {self = [super init];if (self) {self.recursiveLock = [[NSRecursiveLock alloc] init];}return self;
}
- (void)run {NSInteger n = 3;NSLog(@"%ld! = %ld",(long)n, (long)[self sum:3]);
}
- (NSInteger)sum:(NSUInteger)n {[self.recursiveLock lock];NSInteger result = 0;if (n <= 1) {result = n;} else {result = [self sum:n - 1] * n;}[self.recursiveLock unlock];return result;
}
@end

如果将 NSRecursiveLock 换成 NSLock 就会造成死锁。

@synchronized

- (void)lock1 {@synchronized (self) {// 加锁操作}
}

性能最差

iOS - 多线程的锁相关推荐

  1. [iOS] 谈谈iOS多线程的锁

    五花八门的? 前言 iOS开发中由于各种第三方库的高度封装,对锁的使用很少,刚好之前面试中被问到的关于并发编程锁的问题,都是一知半解,于是决定整理一下关于iOS中锁的知识,为大家查缺补漏. 目录 第一 ...

  2. 多线程 循环 锁_大多数人还不清楚的iOS多线程

    你不知道的的 iOS 多线程 程序员用有限的生命去追求无限的知识. 有言在先 首先我不是故意要做标题党的,也不是我要炒冷饭,我只是想换个姿势看多线程,本文大部分内容在分析如何造死锁,奈何功力尚浅,然而 ...

  3. iOS多线程全套:线程生命周期,多线程的四种解决方案,线程安全问题,GCD的使用,NSOperation的使用(上)

    2017-07-08 remember17 Cocoa开发者社区 目的 本文主要是分享iOS多线程的相关内容,为了更系统的讲解,将分为以下7个方面来展开描述. 多线程的基本概念 线程的状态与生命周期 ...

  4. iOS 多线程的四种技术方案

    iOS 多线程的四种技术方案 image pthread 实现多线程操作 代码实现: void * run(void *param) {for (NSInteger i = 0; i < 100 ...

  5. iOS多线程:『NSOperation、NSOperationQueue』详尽总结

    2019独角兽企业重金招聘Python工程师标准>>> iOS多线程:『NSOperation.NSOperationQueue』详尽总结 转载: 原地址https://www.ji ...

  6. IOS 多线程04-GCD详解 底层并发 API

    IOS 多线程04-GCD详解 底层并发 API 注:本人是翻译过来,并且加上本人的一点见解. 前言 想要揭示出表面之下深层次的一些可利用的方面.这些底层的 API 提供了大量的灵活性,随之而来的是大 ...

  7. iOS多线程:『pthread、NSThread』详尽总结

    2019独角兽企业重金招聘Python工程师标准>>> 本文用来介绍 iOS 多线程中,pthread.NSThread 的使用方法及实现. 第一部分:pthread 的使用.其他相 ...

  8. iOS多线程编程之NSThread的使用(★★★推荐,为原作者点赞★★★)

    文章来源:http://blog.csdn.net/totogo2010/article/details/8010231 1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThre ...

  9. iOS 多线程使用示例

    iOS是一款非常流行的移动操作系统,它的多线程特性被广泛应用于各种应用程序中.在本文中,我们将介绍iOS多线程的使用示例,以帮助开发人员更好地理解和应用多线程技术. 多线程概述 在iOS中,多线程是指 ...

最新文章

  1. jqgrid自定义列表开发=》实现高级查询
  2. python 链表的中间节点
  3. easyUI 学习网站
  4. ServletRequest startAsync()的有用性有限
  5. Mybatis之typeAlias配置的3种方法
  6. 为什么rand()+ rand()产生负数?
  7. 8.4 bert的压缩讲解 意境级
  8. vant实现三级联动
  9. 设置win10有线网络连接
  10. C语言IDE和编辑器比较
  11. 【仅供学习研究】网站复制工具+整站镜像克隆工具
  12. 阿里一面:SQL 优化有哪些技巧?
  13. unity3d 不规则外发光描边_PS发光字体教程
  14. 用PS去设计食品网站的展示
  15. 计算机处理数据几进制,计算机内部运行和处理的数据是几进制
  16. 苹果授权登录绑定手机号被拒绝
  17. python处理表格数据教程_利用Python处理Excel数据
  18. vmware虚拟机检测不到vspd虚拟串口问题
  19. mac mini u盘安装系统_用u盘安装win7系统详细步骤
  20. 嫁人就嫁程序猿——钱多话少死的早!很励志。。。

热门文章

  1. 我最喜欢的两首反战诗
  2. snipaste 截图工具——可以使图片悬浮在任何软件上,方便对比
  3. 营收利润双下滑,唯品会正在沉溺
  4. 《算法导论》第23章-最小生成树 23.1-最小生成树的形成
  5. Greenplum Vacuum表的作用
  6. JavaScript实现下雪(Snow)效果
  7. 作为白手起家的企业家,必经阶段你经历了几个?
  8. 苹果电脑如何缩小pdf文件的容量大小?电脑上怎么把pdf文件容量缩小?
  9. 求两条曲线的交点 matlab,matlab求两条曲线交点
  10. 韦恩图进阶之upsetplot:02