GCD 線程安全同步
學(xué)習(xí)盈滴、記錄與分享
GCD 與 NSThread比較
- GCD會自動利用更多的CPU內(nèi)核、 會自動管理線程的生命周期 (創(chuàng)建線程、調(diào)度線程东涡、銷毀線程)開發(fā)者只需用GCD函數(shù)創(chuàng)建任務(wù)哩牍,加入隊列棚潦,GCD會根據(jù)CPU內(nèi)核自動創(chuàng)建線程(創(chuàng)建多少,怎么創(chuàng)建不許要管)去完成任務(wù)膝昆。NSThread需要開發(fā)者自己創(chuàng)建線程去完成任務(wù)丸边。
GCD核心
- 函數(shù):異步和同步
- 任務(wù):創(chuàng)建任務(wù)
- 隊列:將任務(wù)加入隊列(串行隊列、并發(fā)隊列)
隊列
-
并發(fā)隊列
- 隊列里的任務(wù)會自動開啟多個線程并發(fā)執(zhí)行,但是需要異步函數(shù)的任務(wù)才有效
- 隊列只是影響任務(wù)執(zhí)行的方式,實際上并不能決定是否開啟新的線程,僅僅是并發(fā)隊列允許多個線程同時運行,而串行隊列只能是一個一個任務(wù)在同一線程執(zhí)行.
- 創(chuàng)建并發(fā)隊列
//通過直接創(chuàng)建的方式創(chuàng)建,參數(shù)決定是否是并發(fā)隊列
//DISPATCH_QUEUE_CONCURRENT代表并發(fā)隊列
//DISPATCH_QUEUE_SERIAL或NULL代表串行隊列
//標(biāo)示符代表這個隊列的一個標(biāo)記
dispatch_queue_t qune = dispatch_queue_create("創(chuàng)建", DISPATCH_QUEUE_CONCURRENT);
//通過獲取全局隊列來獲得一個并發(fā)隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//這兩個參數(shù),第一個是優(yōu)先級一般用默認(rèn),第二個直接設(shè)為0 是一個保留標(biāo)記,實際作用不大
* 串行隊列
+ 隊列里的任務(wù)會以串行的形式一個一個按順序執(zhí)行
+ 創(chuàng)建串行隊列
//直接創(chuàng)建
//DISPATCH_QUEUE_SERIAL或NULL代表串行隊列
dispatch_queue_t queue = dispatch_queue_create("標(biāo)示符", DISPATCH_QUEUE_SERIAL);
//獲得主隊列,也是一種串行隊列
dispatch_queue_t queue = dispatch_get_main_queue();
#####函數(shù)
* 同步函數(shù):執(zhí)行之后不立即返回荚孵,等待任務(wù)完成才返回妹窖,會阻塞當(dāng)下線程
//queue代表你要放入的隊列
dispatch_sync(queue, ^{
//在這里寫要執(zhí)行的代碼
});
`
* 異步函數(shù):執(zhí)行之后立即返回,不會阻塞當(dāng)下線程
//queue代表你要放入的隊列
dispatch_async(queue, ^{
//在這里寫要執(zhí)行的代碼
});
* 柵欄函數(shù)
//隔斷函數(shù),前面執(zhí)行完才會執(zhí)行這個函數(shù),這個函數(shù)執(zhí)行完才會執(zhí)行其他后面的函數(shù)
dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
####不同的隊列與函數(shù)的組合會有不同的效果
* 并行隊列+異步函數(shù):創(chuàng)建新的線程,并行執(zhí)行任務(wù)
* 并行隊列+同步函數(shù):沒有新的線程,串行執(zhí)行任務(wù)
* 串行隊列+異步函數(shù):創(chuàng)建新的線程,串行執(zhí)行任務(wù)
* 串行隊列+同步函數(shù):沒有新的線程,串行執(zhí)行任務(wù)
* 主隊列+異步函數(shù):沒有新的線程,串行執(zhí)行任務(wù)
* 主隊列+同步函數(shù):沒有新的線程,串行執(zhí)行任務(wù)(主隊列雖然也是串行隊列)
####下面通過GCD實現(xiàn)單一資源線程安全的多讀單寫
#####一 信號量#####
簡單來說就是控制訪問資源的數(shù)量收叶,比如系統(tǒng)有兩個資源可以被利用骄呼,同時有三個線程要訪問,只能允許兩個線程訪問滔驾,第三個應(yīng)當(dāng)?shù)却Y源被釋放后再訪問谒麦。
#####二 使用#####
* 創(chuàng)建信號量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
// 1 是信號量的初始值 這里只允許一個線程訪問
* 提高信號量
dispatch_semaphore_signal(semaphore)
* 等待降低信號量
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// 如果semaphore計數(shù)大于等于1.計數(shù)-1,返回哆致,程序繼續(xù)運行绕德。如果計數(shù)為0,則等待摊阀。
測試
dispatch_queue_t qune = dispatch_queue_create("x", DISPATCH_QUEUE_CONCURRENT);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
__block int i = 1 , n = 1;
for (int index = 0; index < 100; index++) {
dispatch_async(qune, ^(){
i++;
NSLog(@"%d %d\n", index,i);
});
}
/*
只能單寫
*/
for (int index = 0; index < 100; index++) {
dispatch_async(qune, ^(){
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//
n++;
NSLog(@"%d xx %d\n", index,n);
// sleep(1);
dispatch_semaphore_signal(semaphore);
});
}
打印LOG:
2016-09-12 14:32:11.849 Mansory[4745:108806] 0 2
2016-09-12 14:32:11.849 Mansory[4745:108807] 2 4
2016-09-12 14:32:11.849 Mansory[4745:108805] 1 3
2016-09-12 14:32:11.850 Mansory[4745:108887] 3 5
2016-09-12 14:32:11.850 Mansory[4745:108888] 4 6
2016-09-12 14:32:11.851 Mansory[4745:108807] 6 8
2016-09-12 14:32:11.851 Mansory[4745:108806] 5 7
2016-09-12 14:32:11.851 Mansory[4745:108805] 7 9
2016-09-12 14:32:11.851 Mansory[4745:108887] 8 10
2016-09-12 14:32:11.851 Mansory[4745:108888] 9 11
.
.
index 是亂序的 因為是異步的 i值是亂序的 因為資源競爭的問題導(dǎo)致
2016-09-12 14:32:11.863 Mansory[4745:108910] 0 xx 2
2016-09-12 14:32:11.863 Mansory[4745:108807] 99 101
2016-09-12 14:32:11.868 Mansory[4745:108807] 39 xx 3
2016-09-12 14:32:11.868 Mansory[4745:108807] 42 xx 4
2016-09-12 14:32:11.868 Mansory[4745:108807] 43 xx 5
2016-09-12 14:32:11.868 Mansory[4745:108807] 45 xx 6
2016-09-12 14:32:11.868 Mansory[4745:108807] 46 xx 7
2016-09-12 14:32:11.868 Mansory[4745:108807] 48 xx 8
2016-09-12 14:32:11.869 Mansory[4745:108927] 50 xx 9
2016-09-12 14:32:11.869 Mansory[4745:108927] 51 xx 10
2016-09-12 14:32:11.869 Mansory[4745:108927] 53 xx 11
2016-09-12 14:32:11.869 Mansory[4745:108927] 54 xx 12
2016-09-12 14:32:11.869 Mansory[4745:108927] 56 xx 13
2016-09-12 14:32:11.869 Mansory[4745:108927] 57 xx 14
2016-09-12 14:32:11.870 Mansory[4745:108927] 59 xx 15
2016-09-12 14:32:11.870 Mansory[4745:108927] 61 xx 16
.
.
index 是亂序的 是異步的 n值是遞增的有序的 資源安全
#### dispatch_group_t 隊列同步
* 手動管理group關(guān)聯(lián)的block的運行狀態(tài)
dispatch_group_t group = dispatch_group_create();
__weak typeof(self) this = self;
dispatch_group_enter(group);
[this productEvlute]; //網(wǎng)絡(luò)請求
self.requestProductSucess = ^{
//請求成功回調(diào)
dispatch_group_leave(group);
};
dispatch_group_enter(group);
[this estimateServive]; //網(wǎng)絡(luò)請求耗時操作
self.requestServiceSucess = ^{
//請求成功
dispatch_group_leave(group);
};
}
.
.
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//任務(wù)都完成回調(diào)
[this checkIFAllCommitSucess];
});
/*
進(jìn)入dispatch_group_enter和退出dispatch_group_leave次數(shù)必須匹配
*/
*
````
dispatch_group_async(group, queue, ^{
//任務(wù)1
});
dispatch_group_async(group, queue, ^{
//任務(wù)2
});
.
.
dispatch_group_notify (group, queue, ^{
//任務(wù)都complete
});
````