信号量多用于线程同步,加锁等操作。先介绍它的几个函数
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); //创建信号量
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(semaphore);//释放信号量,使其加1
dispatch_semaphore_create 这个函数是用来创建信号量的,传参是个int,一般代表并发数。 为了更好的理解,我们打个比方,dispatch_semaphore_create(N)相当于创建了一个停车场,这个停车场一共有N个车位。dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);代表开进来一辆车(车位个数减一),如果车位个数减一后是负数,那么就会卡死在当前线程,直到DISPATCH_TIME_FOREVER,这个是超时时间,dispatch_semaphore_signal(semaphore) 代表有车开走了,车位加一。空说概念太抽象,我们结合一个例子。
- (void)calcuteAll {
__block NSInteger sourceArrCount = 5;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); //创建信号量
for (NSInteger i = 0; i < sourceArrCount; i++) {
NSLog(@"for循环 i:%ld,sourceArrCount:%ld",i,sourceArrCount);
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"开始任务-线程:%@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
sourceArrCount--;
NSLog(@"soucre的值 %ld",sourceArrCount);
dispatch_semaphore_signal(semaphore);//释放信号量,使其加1
});
//当信号量的值为0时阻塞当前执行,直到值大于0时做减1操作,并执行后续代码
}
NSLog(@"end");
}
大家可以想一想,这个会如何打印?
2019-10-10 15:09:10.405877+0800 c==[8778:226108] for循环 i:0,sourceArrCount:5
2019-10-10 15:09:10.406000+0800 c==[8778:226108] for循环 i:1,sourceArrCount:5
2019-10-10 15:09:10.406055+0800 c==[8778:226167] 开始任务-线程:<NSThread: 0x600002075300>{number = 3, name = (null)}
2019-10-10 15:09:11.408821+0800 c==[8778:226167] soucre的值 4
2019-10-10 15:09:11.409116+0800 c==[8778:226108] for循环 i:2,sourceArrCount:4
2019-10-10 15:09:11.409163+0800 c==[8778:226167] 开始任务-线程:<NSThread: 0x600002075300>{number = 3, name = (null)}
2019-10-10 15:09:12.413658+0800 c==[8778:226167] soucre的值 3
2019-10-10 15:09:12.413930+0800 c==[8778:226108] end
2019-10-10 15:09:12.413971+0800 c==[8778:226167] 开始任务-线程:<NSThread: 0x600002075300>{number = 3, name = (null)}
2019-10-10 15:09:13.415371+0800 c==[8778:226167] soucre的值 2
来分析以下这个过程
<1> for循环 i= 0: sourceArrCount = 5,
执行 NSLog(@"for循环 i:%ld,sourceArrCount:%ld",i,sourceArrCount);
信号量-1,为0,往下执行在子线程开辟一个异步任务A。
<2> for循环 i= 1: sourceArrCount = 5,
执行 NSLog(@"for循环 i:%ld,sourceArrCount:%ld",i,sourceArrCount);
因为信号为0,无法再减一,卡死在主线程
A任务完成,打印
NSLog(@"开始任务-线程:%@",[NSThread currentThread]);
NSLog(@"soucre的值 %ld",sourceArrCount);
source为4,
同时信号量加1,为1,
继续回到上一步,信号减一为0,往下执行,开辟一个异步任务B,
<3> for循环 i= 2: sourceArrCount = 4,
执行 NSLog(@"for循环 i:%ld,sourceArrCount:%ld",i,sourceArrCount);
因为信号量为0,又卡死在主线程,
B任务完成,打印
NSLog(@"开始任务-线程:%@",[NSThread currentThread]);
NSLog(@"soucre的值 %ld",sourceArrCount);
source为3,信号量为1,
继续回到卡死的地方,信号减一为0,往下执行,开辟一个异步任务C,
<4> for循环 i= 3: sourceArrCount = 3,循环结束
打印2019-10-10 15:09:12.413930+0800 c==[8778:226108] end
C任务完成。
信号量使用场景
- (void)calcuteAll {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:100];
// 创建为1的信号量
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
for (int i = 0; i < 10000; i++) {
dispatch_async(queue, ^{
// 等待信号量
//dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
[arrayM addObject:[NSNumber numberWithInt:i]];
// [NSThread sleepForTimeInterval:.3];
NSLog(@"%@--%@",[NSNumber numberWithInt:i],[NSThread currentThread]);
// 发送信号量
//dispatch_semaphore_signal(sem);
});
}
}
如果不加锁,多个线程同时往数组里加数据,会内存错乱,这里相当于给子线程加了个锁,它正在访问数组,其他线程访问不了。
再来介绍下dispatch_group,一共包含如下几个函数
// dispatch_group_t group = dispatch_group_create();
// dispatch_group_enter(group);//
// dispatch_group_leave(group);//任务完成,加1
- (void)calcuteAll {
__block NSInteger number = 0;
dispatch_group_t group = dispatch_group_create();
//A耗时操作
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(3);
number += 2;
NSLog(@"第0个回调");
});
//B网络请求
dispatch_group_enter(group);
[self sendRequestWithCompletion:^(id response) {
number += [response integerValue];
dispatch_group_leave(group);
NSLog(@"第一个回调");
}sleepTime:5];
//C网络请求
dispatch_group_enter(group);
[self sendRequestWithCompletion:^(id response) {
dispatch_group_leave(group);
number += [response integerValue];
NSLog(@"第二个回调");
}sleepTime:2] ;
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"%zd", number);
});
}
dispatch_group_enter 和dispatch_group_leave 成对出现,dispatch_group_leave多的话,会crash。