GCD之信号量dispatch_semaphore

信号量是基于计数器的一种多线程同步机制,用来管理对资源的并发访问。
信号量内部有一个可以原子递增或递减的值。如果一个动作尝试减少信号量的值,使其小于0,那么这个动作将会被阻塞,直到有其他调用者(在其他线程中)增加该信号量的值。
信号量就是一种可用来控制访问资源的数量的标识,设定了一个信号量,在线程访问之前,加上信号量的处理,则可告知系统按照我们指定的信号量数量来执行多个线程。

有点类似锁机制,只不过信号量都是系统帮助我们处理,只需要在执行线程之前,设定一个信号量值,并且在使用时,加上信号量处理方法就行了。

简单来讲 信号量为0则阻塞线程,大于0则不会阻塞。则我们通过改变信号量的值,来控制是否阻塞线程,从而达到线程同步。

dispatch_semaphore相关的3个函数

  • dispatch_semaphore_create
    创建一个Semaphore并初始化信号的总量
/*!
 * @function dispatch_semaphore_create
 * @abstract 创建一个新的信号量
 * @param value 信号量的初始值,传入小于0的数返回NULL
 */
dispatch_semaphore_t
dispatch_semaphore_create(long value);
  • dispatch_semaphore_wait
    可以使总信号量减1,当信号总量为0时就会一直等待(阻塞所在线程),否则就可以正常执行。
/*!
 * @function dispatch_semaphore_wait
 *
 * @abstract 等待信号量
 * Wait (decrement) for a semaphore.
 * @param dsema 创建好的信号量
 * @param timeout 信号等待时间,一般使用DISPATCH_TIME_FOREVER,在得到signal之前一直等待
 */
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
  • dispatch_semaphore_signal
    发送一个信号,让信号总量加1
/*!
 * @function dispatch_semaphore_signal
 *
 * @abstract 提高信号量, 使信号量加1并返回
 * @param dsema 已创建好的信号
 */
dispatch_semaphore_signal(dispatch_semaphore_t dsema);

dispatch_semaphore主要应用于两个方面

  • 线程同步
    直接上代码
- (void)semaphoreTest {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    __block long j = 0;
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 1000; i ++) {
            j ++;
        }
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    NSLog(@"%ld",j);
}
//运行结果:2018-05-23 17:56:48.064 MultiThreadingDemo[2955:535470] 1000

代码说明:block块异步执行添加到了全局并发队列里,所以程序在主线程会跳过block块(同时开辟子线程异步执行block块),执行块外的代码dispatch_semaphore_wait,因为semaphore信号量为0,且时间为DISPATCH_TIME_FOREVER,所以会阻塞当前线程(主线程),进而只执行子线程的block块,直到执行块内部的dispatch_semaphore_signal使得信号量+1。正在被阻塞的线程(主线程)会恢复继续执行。这样保证了线程之间的同步。

  • 为线程加锁,限制并发线程数量
    使用dispatch_semaphore_create(0);保证在同一时间只有一个线程访问,实现加锁功能。关于限制线程数量,我们用一个停车场的demo看一下:
//停车场demo
- (void)parkingAreaADemo {
    //假设目前有3个停车位
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //有10辆车过来打算停车
    for (NSInteger i = 1; i <= 10; i ++) {
        dispatch_async(queue, ^{
            NSInteger carId = i;
            if (carId % 3 == 0) {
                //这几位车主不愿意一直等待,所有设定一个能接受的等待时间
                NSUInteger result = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 8 * carId * NSEC_PER_SEC));
                if (result != 0) {//超时,直接离开
                    NSLog(@"第%ld个车主不等了",carId);
                } else {
                    NSLog(@"第%ld个车主在规定的时间内等到了车位,进入停车场",carId);
                    [NSThread sleepForTimeInterval:10];
                    dispatch_semaphore_signal(semaphore);
                    NSLog(@"第%ld个车主离开,有空位了",carId);
                }
            } else {
                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
                NSLog(@"第%ld个车主进入停车场",carId);
                [NSThread sleepForTimeInterval:10 + i * 10];
                dispatch_semaphore_signal(semaphore);
                NSLog(@"第%ld个车主离开,有空位了",carId);
            }
        });
    }
}

//运行结果
2018-05-24 12:13:55.959 MultiThreadingDemo[1490:186763] 第3个车主离开,有空位了
2018-05-24 12:13:55.959 MultiThreadingDemo[1490:186860] 第4个车主进入停车场
2018-05-24 12:14:05.959 MultiThreadingDemo[1490:186764] 第1个车主离开,有空位了
2018-05-24 12:14:05.959 MultiThreadingDemo[1490:186861] 第5个车主进入停车场
2018-05-24 12:14:15.960 MultiThreadingDemo[1490:186766] 第2个车主离开,有空位了
2018-05-24 12:14:15.960 MultiThreadingDemo[1490:186862] 第6个车主在规定的时间内等到了车位,进入停车场
2018-05-24 12:14:25.962 MultiThreadingDemo[1490:186862] 第6个车主离开,有空位了
2018-05-24 12:14:25.962 MultiThreadingDemo[1490:186863] 第7个车主进入停车场
2018-05-24 12:14:45.966 MultiThreadingDemo[1490:186860] 第4个车主离开,有空位了
2018-05-24 12:14:45.966 MultiThreadingDemo[1490:186864] 第8个车主进入停车场
2018-05-24 12:14:57.961 MultiThreadingDemo[1490:186865] 第9个车主不等了
2018-05-24 12:15:05.964 MultiThreadingDemo[1490:186861] 第5个车主离开,有空位了
2018-05-24 12:15:05.964 MultiThreadingDemo[1490:186866] 第10个车主进入停车场
2018-05-24 12:15:45.968 MultiThreadingDemo[1490:186863] 第7个车主离开,有空位了
2018-05-24 12:16:15.972 MultiThreadingDemo[1490:186864] 第8个车主离开,有空位了
2018-05-24 12:16:55.971 MultiThreadingDemo[1490:186866] 第10个车主离开,有空位了
GCD系列
  • GCD基础
  • GCD进阶函数
  • 调度组dispatch_group
  • 信号量dispatch_semaphore

参考资料:
https://blog.csdn.net/liuyang11908/article/details/70757534
https://www.jianshu.com/p/2d57c72016c6

你可能感兴趣的:(GCD之信号量dispatch_semaphore)