iOS开发信号量的使用
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执行结束