1、NSCondition
NSCondition是对mutex和cond的封装,可以通过 GNUstep源码 中的NSLock.m查看:
@interface NSCondition : NSObject <NSLocking> {
gs_cond_t _condition;
gs_mutex_t _mutex;
NSString *_name;
}
有如下API:
- (void)NSConditionAPI {
// 初始化
NSCondition *condition = [[NSCondition alloc] init];
// 加锁
[condition lock];
// 解锁
[condition unlock];
// 等待
[condition wait];
// 在设定时间钱等待
[condition waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
// 发送信号
[condition signal];
// 发送广播
[condition broadcast];
}
使用方式和mutex+cond相同:
// 线程一:删除数组元素
- (void)__remove {
[self.cond lock];
NSLog(@"线程1: 【加锁】");
if (self.arr.count == 0) {
NSLog(@"线程1: 开始等待(条件不成立,开始休眠,并【解锁】)");
[self.cond wait];
NSLog(@"线程1: 结束等待(接收到条件成立,【加锁】并执行后续操作)");
}
NSLog(@"线程1: 删除元素");
[self.arr removeLastObject];
NSLog(@"线程1:【解锁】");
[self.cond unlock];
}
// 线程二:添加数组元素
- (void)__add {
[self.cond lock];
NSLog(@"线程2: 【加锁】");
NSLog(@"线程2: 添加元素");
[self.arr addObject:@"1"];
NSLog(@"线程2: 通知线程1条件成立");
[self.cond signal];
NSLog(@"线程2: 【解锁】");
[self.cond unlock];
}
*关于cond先调用signal还是先调用unlock问题: 如果先调用signal,线程2还在加锁中,wait方法不会给线程1马上加锁,会等待线程2解锁后在加锁并处理后续操作。 如果先调用unlock,线程2已经解锁,再调用singal,wait方法会马上解锁并处理后续操作。
2、NSConditionLock
NSConditionLock是对NSCondition的进一步封装,可以设置具体的条件值,让线程间实现依赖关系。
可以通过 GNUstep源码 中的NSLock.m查看NSConditionLock底层实现:
@interface NSConditionLock : NSObject <NSLocking>
{
NSCondition *_condition;
int _condition_value;
NSString *_name;
}
*_condition_value默认值为0
// 加锁方法
- (void) lockWhenCondition: (NSInteger)value
{
[_condition lock];
while (value != _condition_value)
{
[_condition wait];
}
}
*通过加锁源码可知,当条件不成立时,也是利用while循环进行等待,所以也可以将NSConditionLock理解成一个“自旋锁”
有如下API:
- (void)NSConditionLockAPI {
// 初始化,设置初始条件,默认为0
NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:1];
// 加锁
[conditionLock lock];
// 解锁
[conditionLock unlock];
// 指定条件时加锁,不然就等待
[conditionLock lockWhenCondition:1];
// 解锁并更新条件
[conditionLock unlockWithCondition:1];
}
应用举例,让三条线程依次执行:
- (void)__one {
[self.conditionLock lockWhenCondition:1];
NSLog(@"%s", __func__);
sleep(1);
[self.conditionLock unlockWithCondition:2];
}
- (void)__two {
[self.conditionLock lockWhenCondition:2];
NSLog(@"%s", __func__);
sleep(1);
[self.conditionLock unlockWithCondition:3];
}
- (void)__three {
[self.conditionLock lockWhenCondition:3];
NSLog(@"%s", __func__);
sleep(1);
[self.conditionLock unlock];
}
~: -[NSConditionLockDemo __one]
~: -[NSConditionLockDemo __two]
~: -[NSConditionLockDemo __three]