iOS - 多线程的锁
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
NSLock
和 NSRecursiveLock
, 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 - 多线程的锁相关推荐
- [iOS] 谈谈iOS多线程的锁
五花八门的? 前言 iOS开发中由于各种第三方库的高度封装,对锁的使用很少,刚好之前面试中被问到的关于并发编程锁的问题,都是一知半解,于是决定整理一下关于iOS中锁的知识,为大家查缺补漏. 目录 第一 ...
- 多线程 循环 锁_大多数人还不清楚的iOS多线程
你不知道的的 iOS 多线程 程序员用有限的生命去追求无限的知识. 有言在先 首先我不是故意要做标题党的,也不是我要炒冷饭,我只是想换个姿势看多线程,本文大部分内容在分析如何造死锁,奈何功力尚浅,然而 ...
- iOS多线程全套:线程生命周期,多线程的四种解决方案,线程安全问题,GCD的使用,NSOperation的使用(上)
2017-07-08 remember17 Cocoa开发者社区 目的 本文主要是分享iOS多线程的相关内容,为了更系统的讲解,将分为以下7个方面来展开描述. 多线程的基本概念 线程的状态与生命周期 ...
- iOS 多线程的四种技术方案
iOS 多线程的四种技术方案 image pthread 实现多线程操作 代码实现: void * run(void *param) {for (NSInteger i = 0; i < 100 ...
- iOS多线程:『NSOperation、NSOperationQueue』详尽总结
2019独角兽企业重金招聘Python工程师标准>>> iOS多线程:『NSOperation.NSOperationQueue』详尽总结 转载: 原地址https://www.ji ...
- IOS 多线程04-GCD详解 底层并发 API
IOS 多线程04-GCD详解 底层并发 API 注:本人是翻译过来,并且加上本人的一点见解. 前言 想要揭示出表面之下深层次的一些可利用的方面.这些底层的 API 提供了大量的灵活性,随之而来的是大 ...
- iOS多线程:『pthread、NSThread』详尽总结
2019独角兽企业重金招聘Python工程师标准>>> 本文用来介绍 iOS 多线程中,pthread.NSThread 的使用方法及实现. 第一部分:pthread 的使用.其他相 ...
- iOS多线程编程之NSThread的使用(★★★推荐,为原作者点赞★★★)
文章来源:http://blog.csdn.net/totogo2010/article/details/8010231 1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThre ...
- iOS 多线程使用示例
iOS是一款非常流行的移动操作系统,它的多线程特性被广泛应用于各种应用程序中.在本文中,我们将介绍iOS多线程的使用示例,以帮助开发人员更好地理解和应用多线程技术. 多线程概述 在iOS中,多线程是指 ...
最新文章
- jqgrid自定义列表开发=》实现高级查询
- python 链表的中间节点
- easyUI 学习网站
- ServletRequest startAsync()的有用性有限
- Mybatis之typeAlias配置的3种方法
- 为什么rand()+ rand()产生负数?
- 8.4 bert的压缩讲解 意境级
- vant实现三级联动
- 设置win10有线网络连接
- C语言IDE和编辑器比较
- 【仅供学习研究】网站复制工具+整站镜像克隆工具
- 阿里一面:SQL 优化有哪些技巧?
- unity3d 不规则外发光描边_PS发光字体教程
- 用PS去设计食品网站的展示
- 计算机处理数据几进制,计算机内部运行和处理的数据是几进制
- 苹果授权登录绑定手机号被拒绝
- python处理表格数据教程_利用Python处理Excel数据
- vmware虚拟机检测不到vspd虚拟串口问题
- mac mini u盘安装系统_用u盘安装win7系统详细步骤
- 嫁人就嫁程序猿——钱多话少死的早!很励志。。。