ViewController () @property (nonatomic, strong) NSMutableArray * array; @property (nonatomic, strong) NSCondition _array) { _array = [NSMutableArray array]; } return _array; } (NSCondition *)condition { _condition) { _condition = [[NSCondition alloc] init]; } return _condition; } //加载 (void)viewDidLoad
NSLock 对象锁 3. dispatch_semaphore 信号量 4.NSCondition 条件锁 5.NSConditionLock 6.NSRecursiveLock 是递归锁 一.synchronized NSCondition NSCondition 的对象实际上作为一个锁和一个线程检查器:锁主要为了当检测条件时保护数据源,执行条件引发的任务;线程检查器主要是根据条件决定是否继续运行线程,即线程是否被阻塞 使用 NSConditon *condition =[ [NSCondition alloc]]init; [condition lock];//一般用于多线程同时访问、修改同一个数据源,保证在同一时间内数据源只被访问 *lock = [[NSCondition alloc] init]; NSMutableArray *array = [[NSMutableArray alloc] init]; //线程1 NSConditionLock与NSCondition大体相同,但是NSConditionLock可以设置锁条件,而NSCondition确只是无脑的通知信号。
因为 GCDAsyncSocket 销毁时,会将 waitUntilDone:YES 当做参数传入,所以,NSCondition 的实例会被创建并用于阻塞当前线程 NSCondition 的实例初始化时 `-[NSCondition wait]: 0x1e08f249c <+0>: stp x29, x30, [sp, #-0x10]! lock]加锁,并通过-[NSCondition signal] 间接调用 pthread_cond_signal 函数的方式恢复另外一个被阻塞的线程 -[NSCondition signal] lock] 和 -[NSCondition wait] -[NSCondition unlock] 实现 -[_NSThreadPerformInfo signal:] 当需要恢复被阻塞的线程时 ,会通过-[_NSThreadPerformInfo signal:] 间接调用-[NSCondition lock] 和 -[NSCondition signal] 实现 -[_NSThreadPerformInfo
通过一个简单的demo来分析iOS中常用的一些锁的性能(@synchronized,NSLock,pthread,OSSpinLock,dispatch_semaphore_t,pthread_mutex_t,NSCondition end = CACurrentMediaTime(); timeCosts = end - begin; pthread_mutex_destroy(&lock); // NSCondition 条件锁 NSCondition *lock = [NSCondition new]; begin = CACurrentMediaTime(); for 上述代码均为加锁解锁的操作,在重复1000000次加锁解锁的基础进行测试(模拟器中),结果数据如下: OSSpinLock os_unfair_lock dispatch_semaphore pthread_mutex NSCondition
对此Foundation提供了NSCondition类来处理多线程之间的通信,NSCondition实现了NSLock协议,因此也可以调用lock、unlock来实现线程同步。 除此之外,NSCondition可以让那些已经锁定NSCondition对象却无法继续执行的线程释放NSCondition对象,NSCondition对象也可以唤醒其他处于等待状态的线程。 NSCondition提供了如下几个方法 //改方法导致当前线程一直等待,直到其他线程调用该NSCondition的signal方法或者broadcast方法 - (void)wait; //用于控制等待到指定时间点 只有当前线程放弃对该NSCondition对象的锁定后(wait方法),才可执行 - (void)signal; //唤醒等待的所有线程 - (void)broadcast; 今天暂时写到这!
NSLock NSLock是最简单的互斥锁,下面的NSCondition、NSConditionLock以及NSRecursiveLock都是遵守了NSLocking协议的,我们就放在一起说 NSCondition条件锁,首先它也是遵循NSLocking协议的,这点和我们上面说的NSLock是一致的,所以它的加锁和解锁方式和我们前面说的NSLock是一样的,就是lock和unlock方法 但我们要是把NSCondition当NSLock用那就真的是浪费了! NSCondition还有自己的wait和signal用法,这个和后面信号量有点点类似,信号量的我们下面再说,看看NSCondition部分的代码: // MARK: - startTestBtnAction NSConditionLock也能像NSCondition一样能进行线程之间的等待调用,并且还是线程安全的。
线程的调度对于开发者来说是透明的,我们不能也无法预测线程执行的顺序,但有时我们需要线程按照一定条件来执行,这时就需要线程间进行通信,NSCondition就提供了线程间通信的方法,查看一下NSCondition 实现了NSLocking协议,所以NSCondition同样具有锁的功能,与NSLock一样可以获取锁与释放锁的操作。 的getter,用于创建NSCondition对象 - (NSCondition*)condition { if (_condition == nil) { _condition = [[NSCondition alloc] init]; } return _condition; } - (void)draw:(id)money { //设置消费者取钱 上面代码的写法是按照苹果官方文档的顺序写的,更多关于NSCondition可查阅官方文档:Apple NSCondition 备注 由于作者水平有限,难免出现纰漏,如有问题还请不吝赐教。
4、 NSCondition 基于信号量方式实现的锁对象,提供单独的信号量管理接口。底层通过pthread_cond_t实现。 NSCondition对象包含锁和条件检测功能,类似于生产者和消费者:消费者消费资源如果没有就继续等待,生产者提供资源然后发出信号激活消费者。锁的作用就是用来保护这一操作防止被其他线程干扰。 DEMO: isWait = true; condition = [[NSCondition alloc]init]; __weak typeof(self) weakSelf 输出结果: [13781:212898] 等待条件满足 [13781:212898] 执行操作 [13781:212898] 完成 5、 NSConditionLock 可以使用特定值来加锁和解锁,和NSCondition 使用上比NSCondition更方便些,代码更简洁。
init]; // 加锁 [_lock lock]; // 解锁 [_lock unlock]; // 尝试加锁,可以加锁则立即加锁并返回 YES,反之返回 NO [_lock tryLock]; 6、NSCondition (条件锁、对象锁) // 初始化 NSCondition *_condition= [[NSCondition alloc]init]; // 加锁 [_condition lock]; // 解锁 [ pthread_cond_wait(&_cond, &_mutex); // 信号 pthread_cond_signal(&_cond); // 广播 pthread_cond_broadcast(&_cond); 像NSCondition 封装了pthread_mutex的以上几个函数,NSConditionLock封装了NSCondition 4、递归锁 递归锁的主要意思是,同一条线程可以加多把锁.什么意思呢,就是相同的线程访问一段代码
使用NSCondition类 NSCondition类提供与POSIX条件相同的语义,但将所需的锁和条件数据结构都封装在一个对象中。结果是,您可以像互斥体一样锁定对象,然后像条件一样等待。 清单4-3显示了一个代码片段,演示等待一个NSCondition对象的事件序列。 cocoaCondition变量包含一个NSCondition对象,timeToDoWork变量是一个整数,在发出条件信号之前从另一个线程递增。 : 16.867995 ms os_unfair_lock_lock: 15.706062 ms pthread_mutex_t: 17.253995 ms NSlock: 18.406034 ms NSCondition : 29.148102 ms os_unfair_lock_lock: 20.449996 ms pthread_mutex_t: 32.608032 ms NSlock: 32.607913 ms NSCondition
使用NSCondition实现线程间通讯 大家还记得GCD中的信号量(semaphore)嘛?不记得话看看喽,传输门:Swift多线程:GCD进阶,单例、信号量、任务组 。 Thread里面的NSCondition和这个有点像。 使线程处于等待状态 wait(until limit: Date) -> Bool 在给定的时间到达时仍未有信号量出现, 就自动继续了 signal 唤醒线程 broadcast 唤醒所有等待线程 NSCondition let imageCondition = NSCondition() let articleCondition = NSCondition() override func viewDidLoad
url=[NSURL URLWithString:name]; data=[NSData dataWithContentsOfURL:url]; } return data; } NSCondition 实现控制线程通信 NSCondition 的对象实际上作为一个锁和一个线程检查器:锁主要为了当检测条件时保护数据源,执行条件引发的任务;线程检查器主要是根据条件决定是否继续运行线程,即线程是否被阻塞 单纯解决线程同步问题不是NSCondition设计的主要目的,NSCondition更重要的是解决线程之间的调度关系(当然,这个过程中也必须先加锁、解锁)。 NSCondition可以调用wati方法控制某个线程处于等待状态,直到其他线程调用signal(此方法唤醒一个线程,如果有多个线程在等待则任意唤醒一个)或者broadcast(此方法会唤醒所有等待线程 //初始化锁对象 _condition=[[NSCondition alloc]init]; #pragma mark 创建图片 -(void)createImageName{ [
NSCondition NSCondition是通过pthread中的条件变量(condition variable) pthread_cond_t来实现的。 而NSCondition其实就是封装了一个互斥锁和条件变量,互斥锁的lock/unlock方法和后者的wait/signal统一封装在 NSCondition对象中,暴露给使用者。 我们可以刚好可以使用 NSCondition解决生产者-消费者问题。具体的代码放置在文末的 Demo 里了。 这里需要注意,实际操作NSCondition做 wait操作时,如果用if判断: if(count==0){ [condition wait]; } 上面这样是不能保证消费者是线程安全的。 因为NSCondition可以给每个线程分别加锁,但加锁后不影响其他线程进入临界区。所以 NSCondition使用 wait并加锁后,并不能真正保证线程的安全。
尝试是否可以加锁 如果可以 直接加锁返回YES - (BOOL)lockBeforeDate:(NSDate *)limit; //在一定时间内是否可以加锁 如果可以 直接加锁返回YES 复制代码 6、NSCondition NSCondition是对mutex和cond的封装 //用法和mutex condtion 一样 可以参考上面代码 - (void)lock;// 加锁 - (void)unlock;//解锁 - 如果超时就不等了 就直接执行 - (void)signal; // 信号量 - (void)broadcast; //广播 复制代码 7、NSConditionLock NSConditionLock是对NSCondition
相信仔细的大家肯定在锁的用法里面见过NSCondition,就是封装了条件变量pthread_cond_t和互斥锁 - (void) signal { pthread_cond_signal( 其实这个函数是通过宏来定义的,展开后就是这样 - (void) lock { int err = pthread_mutex_lock(&_mutex); } 复制代码 NSConditionLock借助 NSCondition NSConditionLock 的内部持有一个NSCondition对象,以及 _condition_value属性,在初始化时就会对这个属性进行赋值: // 简化版代码 - (id) initWithCondition = (self = [super init])) { _condition = [NSCondition new] _condition_value = value;
self.items addObject:items[i]]; NSLog(@"%@", self.items); [self.lock unlock]; // 解锁 }); } 6、NSCondition 使用例子: NSCondition *lock = [[NSCondition alloc] init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
相信仔细的大家肯定在锁的用法里面见过NSCondition,就是封装了条件变量pthread_cond_t和互斥锁 - (void) signal { pthread_cond_signal( 其实这个函数是通过宏来定义的,展开后就是这样 - (void) lock { int err = pthread_mutex_lock(&_mutex); } NSConditionLock借助 NSCondition NSConditionLock 的内部持有一个NSCondition对象,以及 _condition_value属性,在初始化时就会对这个属性进行赋值: // 简化版代码 - (id) initWithCondition = (self = [super init])) { _condition = [NSCondition new] _condition_value = value;
OSSpinLock(自旋锁) -> os_unfair_lock(互斥锁) ->dispatch_semaphore_t(信号量) -> pthread_mutex(互斥锁) -> NSLock(互斥锁) -> NSCondition 真机(软件版本:13.7) 真机情况目前测试性能高低如下OSSpinLock(自旋锁) -> os_unfair_lock(互斥锁) -> dispatch_semaphore_t(信号量) -> NSCondition
deinit { // 销毁锁 pthread_mutex_destroy(&mutex) } NS系列锁 包括NSLock、NSCondition、NSConditionLock、NSRecursiveLock // 初始化 let lock = NSLock() // 加锁 lock.lock() // 临界区 // 解锁 lock.unlock() NSCondition:常用于生产者消费者模式。 // 初始化 let lock = NSCondition() var products = [Int]() // 消费者 func consume() { DispatchQueue.global lock.unlock() } } while true { consume() sleep(1) produce() } NSConditionLock:条件锁,对 NSCondition
就差不多了 在需要递归调用的方法或者函数中使用的锁,一定要使用递归锁,比如NSRecursiveLock 在循环多线程的情形下,一定要注意死锁的情形,必要的话使用@synchronized来代替其他的互斥锁 NSCondition ]; NSLog(@"线程 3"); [conditionLock unlock]; }); 执行后打印结果为: 2021-03-24 17:23:12.962065+0800 004-NSCondition [8242:1558008] 线程 3 2021-03-24 17:23:12.977179+0800 004-NSCondition[8242:1558008] 线程 2 2021-03-24 17: 23:13.040493+0800 004-NSCondition[8242:1558006] 线程 1 分析如下: 首先在主线程依次添加了三个任务到全局队列,这三个任务的优先级由高到低依次为:线程1>