1、GCD提供了一種信號量機制,我們可以用它來做線程的同步控制。
信號量的工作機制:
信號量支持“信號通知”和“等待”兩個操作,初始化時會給信號量一個初始整形值,他代表線程可以訪問的資源數。信號量被通知,值加一,當一個線程被信號量控制為等待,線程會被阻塞,直到信號量計數值大於0,然后線程會減少這個計數。
GCD提供了3個信號量操作:
//創建信號,5是信號總量
dispatch_semaphore_create(5);
//發送一個信號,信號量+1
dispatch_semaphore_signal(semphore)
//等待信號
dispatch_semaphore_wait(semphore, DISPATCH_TIME_FOREVER)
2、使用場景
1、快速創建一個並發控制,和有限資源訪問控制。
- (void)testSemaphore1 {
//創建計數為1的信號量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
//線程A
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//等待,如果信號量大於0,那么繼續往下執行並減少一個信號量
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//耗時操作模擬
[NSThread sleepForTimeInterval:5];
NSLog(@"線程A=%@", [NSThread currentThread]);
//信號加1
dispatch_semaphore_signal(semaphore);
});
//線程B
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//等待,如果信號量大於0,那么繼續往下執行並減少一個信號量
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//耗時操作模擬
[NSThread sleepForTimeInterval:5];
NSLog(@"線程B=%@", [NSThread currentThread]);
//信號加1
dispatch_semaphore_signal(semaphore);
});
}
打印日志:
2021-03-11 17:31:09.895460+0800 Demo[66780:1352656] 線程A=<NSThread: 0x6000024c83c0>{number = 7, name = (null)}
2021-03-11 17:31:14.898532+0800 Demo[66780:1352655] 線程B=<NSThread: 0x6000024ffb80>{number = 6, name = (null)}
2、使用信號量實現任務2依賴任務1。任務1和2都是異步提交的
具體實現:創建信號量並初始化為0,讓任務2執行前等待信號,實現對任務2的阻塞。任務1完成后再發送信號,信號量
值為1,從而任務2獲得執行權。
- (void)testSemaphore2 {
//創建計數為0的信號量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
//任務1
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//耗時操作模擬
NSLog(@"任務1開始執行");
[NSThread sleepForTimeInterval:5];
NSLog(@"任務1執行結束");
//信號加1
dispatch_semaphore_signal(semaphore);
});
//任務2
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//等待,如果信號量大於0,那么繼續往下執行並減少一個信號量
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//耗時操作模擬
NSLog(@"任務2開始執行");
[NSThread sleepForTimeInterval:5];
NSLog(@"任務2執行結束");
});
}
執行順序日志:
2021-03-11 17:50:30.095164+0800 Demo[67625:1373615] 任務1開始執行
2021-03-11 17:50:35.100431+0800 Demo[67625:1373615] 任務1執行結束
2021-03-11 17:50:35.100935+0800 Demo[67625:1373613] 任務2開始執行
2021-03-11 17:50:40.105960+0800 Demo[67625:1373613] 任務2執行結束
3、通過信號量控制線程的最大並發數量
GCD不像NSOperation 那樣具有自帶控制線程最大並發數量的機制和參數。不過可以通過信號量機制來控制。
實現思路:創建信號量,並初始化信號量為想要控制的最大並發數量。然后在每個任務執行前進行P操作【等待】;每個任務執行結束后進行V操作。這樣,始終保持信號量的值在5以內。從而實現最大並發數的控制。
- (void)testSemaphore3 {
//創建計數為5的信號量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(5);
//模擬1000個等待執行的任務,通過信號量控制最大並發任務數量為5
for(int i = 0; i < 1000; i++) {
/*任務i*/
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//耗時任務i,執行前等待,並減少一個信號量
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//耗時操作模擬
NSLog(@"任務%d開始執行",i);
[NSThread sleepForTimeInterval:5];
NSLog(@"任務%d執行結束",i);
/*任務i結束,發送信號量釋放一個資源*/
dispatch_semaphore_signal(semaphore);
});
}
}
日志打印 可以發現,執行狀態的同時最多有5個
2021-03-11 17:54:09.127336+0800 Demo[67787:1378009] 任務1開始執行
2021-03-11 17:54:09.127375+0800 Demo[67787:1378007] 任務3開始執行
2021-03-11 17:54:09.127375+0800 Demo[67787:1378010] 任務2開始執行
2021-03-11 17:54:09.127388+0800 Demo[67787:1378008] 任務0開始執行
2021-03-11 17:54:09.127660+0800 Demo[67787:1378005] 任務4開始執行
2021-03-11 17:54:14.134378+0800 Demo[67787:1378010] 任務2執行結束
2021-03-11 17:54:14.134472+0800 Demo[67787:1378007] 任務3執行結束
2021-03-11 17:54:14.134509+0800 Demo[67787:1378009] 任務1執行結束
2021-03-11 17:54:14.134529+0800 Demo[67787:1378008] 任務0執行結束
2021-03-11 17:54:14.134544+0800 Demo[67787:1378005] 任務4執行結束
2021-03-11 17:54:14.136361+0800 Demo[67787:1378103] 任務5開始執行
2021-03-11 17:54:14.136536+0800 Demo[67787:1378104] 任務6開始執行
2021-03-11 17:54:14.136733+0800 Demo[67787:1378105] 任務7開始執行
2021-03-11 17:54:14.136641+0800 Demo[67787:1378106] 任務8開始執行
2021-03-11 17:54:14.136825+0800 Demo[67787:1378107] 任務9開始執行
2021-03-11 17:54:19.140515+0800 Demo[67787:1378103] 任務5執行結束
2021-03-11 17:54:19.140572+0800 Demo[67787:1378104] 任務6執行結束
2021-03-11 17:54:19.140769+0800 Demo[67787:1378108] 任務10開始執行
2021-03-11 17:54:19.140771+0800 Demo[67787:1378109] 任務11開始執行
2021-03-11 17:54:19.141722+0800 Demo[67787:1378106] 任務8執行結束