iOS开发-dispatch_semaphore(信号量)

前言

假设,现在系统有两个空闲资源可以被利用,但同一时间却有三个线程要进行访问,这种情况下,该如何处理呢?

或者我们需要并发异步下载很多资源,每次下载都可能会开辟一个线程,线程一多就会影响cpu,那么我们就可以用信号量控制一下最大开辟线程数。简单来说就是使用信号量来控制并发。

信号量是一个整形值并且具有一个初始计数值,并且支持两个操作:信号通知和等待

信号量函数

1、创建信号量:

dispatch_semaphore_t dispatch_semaphore_create(long value);

创建一个整形的信号总量, 参数value必须≥0,<0时的值将创建失败返回NULL。

而value值意味可以有多少个并发的线程在同时运行。

2、信号量等待:

long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);

使一个信号量等待,即减少一个信号总量。 减少后,如果信号总量小于零,该线程会被阻塞,会等待到信号总量大于等于0时返回,该线程继续执行。

参数dsema传递NULL的结果未定义,参数timeout可以传递 DISPATCH_TIME_NOW 和 DISPATCH_TIME_FOREVER 或者自己创建一个dispatch_time_t。

  • DISPATCH_TIME_NOW:超时时间为0,表示忽略信号量,直接运行。
  • DISPATCH_TIME_FOREVER:超时时间为永远,表示会一直等待信号量为正数,才会继续运行。

3、 信号量增加(通知):

long dispatch_semaphore_signal(dispatch_semaphore_t dsema);

增加一个信号量,会通知并唤醒正在等待的线程。

比喻

关于信号量使用停车场来比喻比较容易理解。

创建信号量时传入value = 5,代表停车场有5个停车位并且是空车位。

此时来了一辆车占用了一个停车位,即信号量等待一次,一直到来了第6辆车,此时停车场停满了,第6辆车就需要在外面等待,直到有车离开空出一个停车位,即信号量增加,第6辆车才能进去停车。

就是这么简单的一个过程。

示例

正常的使用顺序是先等待然后再增加,dispatch_semaphore_wait() 和 dispatch_semaphore_signal() 需要成对使用。

dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
for (NSInteger i=0; i<10;i++) {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        sleep(1);
        NSLog(@"%@ todo:%ld", [NSThread currentThread],i);
        dispatch_semaphore_signal(semaphore);
    });
}

log:三个一组,每组间隔一秒。

2019-11-30 19:20:19.503027+0800 <NSThread: 0x281b61f80>{number = 4, name = (null)} todo:2
2019-11-30 19:20:19.503288+0800 <NSThread: 0x281b5ce40>{number = 5, name = (null)} todo:1
2019-11-30 19:20:19.503038+0800 <NSThread: 0x281b64ac0>{number = 3, name = (null)} todo:0

2019-11-30 19:20:20.509158+0800 <NSThread: 0x281b43300>{number = 6, name = (null)} todo:3
2019-11-30 19:20:20.509206+0800 <NSThread: 0x281b5c1c0>{number = 7, name = (null)} todo:4
2019-11-30 19:20:20.509908+0800 <NSThread: 0x281b43580>{number = 8, name = (null)} todo:5

2019-11-30 19:20:21.515249+0800 <NSThread: 0x281b5de80>{number = 9, name = (null)} todo:6
2019-11-30 19:20:21.515290+0800 <NSThread: 0x281b434c0>{number = 10, name = (null)} todo:8
2019-11-30 19:20:21.516126+0800 <NSThread: 0x281b5cf00>{number = 11, name = (null)} todo:7

2019-11-30 19:20:22.518671+0800 <NSThread: 0x281b432c0>{number = 12, name = (null)} todo:9

还有一种用法就是初始化信号量为0,是为了使异步变为同步。

iOS开发-block异步实现return

猜你喜欢

转载自blog.csdn.net/qq_36557133/article/details/103326930