一、定义
-
1、信号量:就是一种可用来控制访问资源的数量的标识,设定了一个信号量,在线程访问之前,加上信号量的处理,则可告知系统按照我们指定的信号量数量来执行多个线程。
其实,这有点类似锁机制了,只不过信号量都是系统帮助我们处理了,我们只需要在执行线程之前,设定一个信号量值,并且在使用时,加上信号量处理方法就行了。 -
2、简单来讲 信号量为0则阻塞线程,大于0则不会阻塞。则我们通过改变信号量的值,来控制是否阻塞线程,从而达到线程同步
-
3、信号量主要有3个函数,分别是:
//创建信号量,参数:信号量的初值,如果小于0则会返回NULL dispatch_semaphore_create(信号量值) //等待降低信号量 dispatch_semaphore_wait(信号量,等待时间) //提高信号量 dispatch_semaphore_signal(信号量)
-
4、关于信号量,一般可以用停车来比喻
停车场剩余4个车位,那么即使同时来了四辆车也能停的下。如果此时来了五辆车,那么就有一辆需要等待。信号量的值就相当于剩余车位的数目。
dispatch_semaphore_wait
函数就相当于来了一辆车,dispatch_semaphore_signal
就相当于走了一辆车。停车位的剩余数目在初始化的时候就已经指明了(dispatch_semaphore_create(long value)
),调用一次dispatch_semaphore_signal
,剩余的车位就增加一个;调用一次dispatch_semaphore_wait
剩余车位就减少一个;当剩余车位为0时,再来车(即调用dispatch_semaphore_wait
)就只能等待。有可能同时有几辆车等待一个停车位。有些车主没有耐心,给自己设定了一段等待时间,这段时间内等不到停车位就走了,如果等到了就开进去停车。而有些车主就像把车停在这,所以就一直等下去。
二、使用场景1
假设现在系统有两个空闲资源可以被利用,但同一时间却有三个线程要进行访问,这种情况下,该如何处理呢?
//crate的value表示,最多几个资源可访问
dispatch_semaphore_t samphore = dispatch_semaphore_create(2);
dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//dispatch_queue_t quene = dispatch_queue_create("com.anji.jiajia", DISPATCH_QUEUE_CONCURRENT);
//任务1
dispatch_async(quene, ^{
dispatch_semaphore_wait(samphore, DISPATCH_TIME_FOREVER);
NSLog(@"run task 1");
sleep(1);
NSLog(@"completed task 1");
dispatch_semaphore_signal(samphore);
});
//任务2
dispatch_async(quene, ^{
dispatch_semaphore_wait(samphore, DISPATCH_TIME_FOREVER);
NSLog(@"run task 2");
sleep(1);
NSLog(@"completed task 2");
dispatch_semaphore_signal(samphore);
});
//任务3
dispatch_async(quene, ^{
dispatch_semaphore_wait(samphore, DISPATCH_TIME_FOREVER);
NSLog(@"run task 3");
sleep(1);
NSLog(@"completed task 3");
dispatch_semaphore_signal(samphore);
});
运行结果:
2017-12-20 13:35:34.308282+0800 OCDemo[61949:15613320] run task 1
2017-12-20 13:35:34.308291+0800 OCDemo[61949:15613317] run task 2
2017-12-20 13:35:35.310784+0800 OCDemo[61949:15613320] completed task 1
2017-12-20 13:35:35.310784+0800 OCDemo[61949:15613317] completed task 2
2017-12-20 13:35:35.311016+0800 OCDemo[61949:15613319] run task 3
2017-12-20 13:35:36.313924+0800 OCDemo[61949:15613319] completed task 3
三、使用场景2
我们要下载很多图片,并发异步进行,每个下载都会开辟一个新线程,可是我们又担心太多线程肯定cpu吃不消,那么我们这里也可以用信号量控制一下最大开辟线程数。
//crate的value表示,最多几个资源可访问
dispatch_semaphore_t samphore = dispatch_semaphore_create(5);
dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 15; i++) {
dispatch_async(quene, ^{
dispatch_semaphore_wait(samphore, DISPATCH_TIME_FOREVER);
NSLog(@"run task %d", i);
[self downloadImge:^(BOOL isSuccess, NSString *errorMsg) {
NSLog(@"BLock completed %d", i);
dispatch_semaphore_signal(samphore);
}];
});
}
由于是异步执行的,所以每次循环Block就会执行dispatch_semaphore_wait
,从而semaphore-1
.当循环5次后semaphore==0
,则会阻塞线程,直到执行了Block的dispatch_semaphore_signal
才会继续执行。
四、使用场景3
在开发中我们需要处理下载多张照片等待所有网络回调完之后才执行后面的操作。或者等待多个网络请求,所有请求成功后数据融合处理。
//crate的value表示,最多几个资源可访问
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 5; i++) {
dispatch_group_async(group, quene, ^{
dispatch_semaphore_t samphore = dispatch_semaphore_create(0);
[self downloadImge:^(BOOL isSuccess, NSString *errorMsg) {
NSLog(@"task %d completed ", i);
dispatch_semaphore_signal(samphore);
}];
dispatch_semaphore_wait(samphore, DISPATCH_TIME_FOREVER);
});
}
dispatch_group_notify(group, quene, ^{
NSLog(@"All task completed ====");
});
运行结果:
2017-12-20 14:22:03.162137+0800 OCDemo[64177:15790354] task 0 completed
2017-12-20 14:22:03.162138+0800 OCDemo[64177:15790351] task 3 completed
2017-12-20 14:22:04.165827+0800 OCDemo[64177:15790352] task 2 completed
2017-12-20 14:22:05.167003+0800 OCDemo[64177:15790368] task 4 completed
2017-12-20 14:22:05.166964+0800 OCDemo[64177:15790353] task 1 completed
2017-12-20 14:22:05.167153+0800 OCDemo[64177:15790368] All task completed ====
网友评论