一,NSCondition
1,簡(jiǎn)介:
NSCondition
條件鎖,顧名思義,就是滿足某些條件才會(huì)開(kāi)鎖。NSCondition,可以確保線程僅在滿足特定條件時(shí)才能獲取鎖。一旦獲得了鎖并執(zhí)行了代碼的關(guān)鍵部分,線程就可以放棄該鎖并將關(guān)聯(lián)條件設(shè)置為新的條件。條件本身是任意的:可以根據(jù)應(yīng)用程序的需要定義它們。
NSCondition對(duì)象實(shí)際上作為一個(gè)鎖和一個(gè)線程檢查器:鎖主要為了當(dāng)檢測(cè)條件時(shí)保護(hù)數(shù)據(jù)源,執(zhí)行條件引發(fā)的任務(wù);線程檢查器主要是根據(jù)條件決定是否繼續(xù)運(yùn)行線程,即線程是否被阻塞。通俗的說(shuō),也就是條件成立,才會(huì)執(zhí)行鎖住的代碼。條件不成立時(shí),線程就會(huì)阻塞,直到另一個(gè)線程向條件對(duì)象發(fā)出信號(hào)解鎖為止。
2,方法:
//一般用于多線程同時(shí)訪問(wèn)、修改同一個(gè)數(shù)據(jù)源,保證在同一時(shí)間內(nèi)數(shù)據(jù)源只被訪問(wèn)、修改一次,其他線程的命令需要在lock 外等待,只到unlock ,才可訪問(wèn)
[condition lock];
//與lock 同時(shí)使用
[condition unlock];
//讓當(dāng)前線程處于等待狀態(tài)
[condition wait];
//CPU發(fā)信號(hào)告訴線程不用在等待,可以繼續(xù)執(zhí)行
[condition signal];
3,示例:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) NSCondition *condition;
@property (nonatomic, strong) NSMutableArray *collector;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.condition = [[NSCondition alloc] init];
self.collector = [[NSMutableArray alloc] initWithCapacity:0];
[self test];
}
- (void)test {
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(0, DISPATCH_QUEUE_PRIORITY_DEFAULT), ^{
while (true) {
[weakSelf.condition lock];
if (weakSelf.collector.count > 0 ) {
[weakSelf.condition wait];
}
[weakSelf.collector addObject:@"商品"];
NSLog(@"生產(chǎn):商品");
[weakSelf.condition signal];
[weakSelf.condition unlock];
}
});
dispatch_async(dispatch_get_global_queue(0, DISPATCH_QUEUE_PRIORITY_DEFAULT), ^{
while (true) {
[weakSelf.condition lock];
if (weakSelf.collector.count == 0 ) {
[weakSelf.condition wait];
}
NSString *item = [weakSelf.collector objectAtIndex:0];
NSLog(@"消費(fèi):%@",item);
[weakSelf.collector removeObjectAtIndex:0];
[weakSelf.condition signal];
[weakSelf.condition unlock];
}
});
}
@end
4,解析:
當(dāng)collector.count == 0時(shí), 消費(fèi)線程condition調(diào)用wait進(jìn)入等待狀態(tài)。生產(chǎn)線程生產(chǎn)商品后condition調(diào)用signal,釋放信號(hào),使處于等待的消費(fèi)線程喚醒。這時(shí)collector.count > 0,生產(chǎn)線程condition調(diào)用wait進(jìn)入等待狀態(tài)。消費(fèi)線程消費(fèi)商品后調(diào)用signal,釋放信號(hào),使生產(chǎn)線程喚醒開(kāi)始生產(chǎn)...,從而不斷生產(chǎn)、消費(fèi)、生產(chǎn)、消費(fèi)的流程。
一,NSConditionLock
1,簡(jiǎn)介:
NSConditionLock對(duì)NSCondition又做了一層封裝,自帶條件探測(cè),能夠更簡(jiǎn)單靈活的使用。
2,示例:
NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:2];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[conditionLock lockWhenCondition:1];
NSLog(@"線程1");
[conditionLock unlockWithCondition:0];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
[conditionLock lockWhenCondition:2];
NSLog(@"線程2");
[conditionLock unlockWithCondition:1];
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[conditionLock lock];
NSLog(@"線程3");
[conditionLock unlock];
});
3,解析:
線程1調(diào)用[NSConditionLock lockWhenCondition:],此時(shí)此刻因?yàn)椴粷M足當(dāng)前條件,所以會(huì)進(jìn)入等待狀態(tài)。此時(shí)當(dāng)前的線程3調(diào)用[NSConditionLock lock:],本質(zhì)上是調(diào)用 [NSConditionLock lockBeforeDate:],這里不需要比對(duì)條件值,所以線程 3會(huì)打印。接下來(lái)線程2執(zhí)行[NSConditionLock lockWhenCondition:],因?yàn)闈M足條件值,所以線程2會(huì)打印,打印完成后會(huì)調(diào)用[NSConditionLock unlockWithCondition:],這個(gè)時(shí)候?qū)l件設(shè)置為 1,并發(fā)送boradcast, 此時(shí)線程1接收到當(dāng)前的信號(hào),喚醒執(zhí)行并打印。
自此當(dāng)前打印為 線程 3->線程 2 -> 線程 1。
[NSConditionLock lockWhenCondition:]:這里會(huì)根據(jù)傳入的condition 值和value值進(jìn)行對(duì)比,如果不相等,這里就會(huì)阻塞。而[NSConditionLock unlockWithCondition:]會(huì)先更改當(dāng)前的value值,然后調(diào)用boradcast,喚醒當(dāng)前的線程。
一,總結(jié)
相同點(diǎn):
1,都是互斥鎖
2,通過(guò)條件變量來(lái)控制加鎖、釋放鎖,從而達(dá)到阻塞線程、喚醒線程的目的
不同點(diǎn):
1,NSCondition是基于對(duì)pthread_mutex的封裝,而NSConditionLock是對(duì)NSCondition做了一層封裝
2,NSCondition是需要手動(dòng)讓線程進(jìn)入等待狀態(tài)阻塞線程、釋放信號(hào)喚醒線程
NSConditionLock則只需要外部傳入一個(gè)值,就會(huì)依據(jù)這個(gè)值進(jìn)行自動(dòng)判斷是阻塞線程還是喚醒線程
參考鏈接:
http://www.itdecent.cn/p/0c981352b6d2
http://www.itdecent.cn/p/53a04d5982fe
http://www.itdecent.cn/p/5d20c15ae690