在UNIX環(huán)境下淤井,多線程同步的技術(shù)有mutex
布疼、condition variable
摊趾、semaphore
、RW Lock
游两、spin Lock
等砾层。在iOS平臺(tái)上,可以使用dispatch_semaphore_t
做線程同步贱案。
dispatch_semaphore_t
的原理類似于semaphore
肛炮,與其相關(guān)的方法主要是:
dispatch_semaphore_t dispatch_semaphore_create(long value);
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
long dispatch_semaphore_signal(dispatch_semaphore_t dsema);
dispatch_semaphore_create####
創(chuàng)建一個(gè)新的信號(hào)量,參數(shù)value代表信號(hào)量資源池的初始數(shù)量宝踪。
value < 0侨糟, 返回NULL
value = 0, 多線程在等待某個(gè)特定線程的結(jié)束。
value > 0, 資源數(shù)量瘩燥,可以由多個(gè)線程使用秕重。
dispatch_semaphore_wait####
等待資源釋放。如果傳入的dsema大于0厉膀,就繼續(xù)向下執(zhí)行溶耘,并將信號(hào)量減1;如果dsema等于0服鹅,阻塞當(dāng)前線程等待資源被dispatch_semaphore_signal釋放凳兵。如果等到了信號(hào)量,繼續(xù)向下執(zhí)行并將信號(hào)量減1企软,如果一直沒有等到信號(hào)量庐扫,就等到timeout再繼續(xù)執(zhí)行。dsema不能傳入NULL澜倦。
timeout表示阻塞的時(shí)間長短聚蝶,有兩個(gè)常量:DISPATCH_TIME_NOW
表示當(dāng)前,DISPATCH_TIME_FOREVER
表示永遠(yuǎn)藻治〉饷悖或者自己定義一個(gè)時(shí)間:
dispatch_time_t t = dispatch_time(DISPATCH_TIME_NOW, 1*1000*1000*1000);
dispatch_semaphore_signal####
釋放一個(gè)資源。返回值為0表示沒有線程等待這個(gè)信號(hào)量桩卵;返回值非0表示喚醒一個(gè)等待這個(gè)信號(hào)量的線程验靡。如果線程有優(yōu)先級,則按照優(yōu)先級順序喚醒線程雏节,否則隨機(jī)選擇線程喚醒胜嗓。
應(yīng)用場景####
dispatch_semaphore_t的應(yīng)用場景很多,這里以一個(gè)異步網(wǎng)絡(luò)請求為例钩乍。
在異步網(wǎng)絡(luò)請求中辞州,我們先發(fā)送網(wǎng)絡(luò)請求,然后要等待網(wǎng)絡(luò)結(jié)果返回再做其他事情寥粹。為了將這種異步請求改成同步的变过,我們可以使用dispatch_semaphore_t埃元。
static dispatch_semaphore_t match_sema;
- (void)asynNetWorkRequest {
/*
...
構(gòu)造網(wǎng)絡(luò)請求參數(shù)
...
[[IosNet sharedInstance] asyncCall:method forParam:reqData forCallback:zuscallback forTimeout:timeoutValue];
...
*/
//創(chuàng)建信號(hào)量,阻塞當(dāng)前線程
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
match_sema = dispatch_semaphore_create(0);
});
dispatch_semaphore_wait(match_sema, DISPATCH_TIME_FOREVER);
}
//請求成功 釋放信號(hào)量媚狰,繼續(xù)當(dāng)前線程
- (void)onCallSuccess:(NSData *)rspData {
if (match_sema) {
dispatch_semaphore_signal(match_sema);
}
}
//請求失敗 釋放信號(hào)量岛杀,繼續(xù)當(dāng)前線程
- (void)onCallFail:(NSError *)errorInfo {
if (match_sema) {
dispatch_semaphore_signal(match_sema);
}
}
有一點(diǎn)需要注意,dispatch_semaphore_wait
與 異步操作不能在同一個(gè)線程中崭孤,否則異步操作會(huì)被卡住类嗤,也就不會(huì)執(zhí)行到dispatch_semaphore_signal