美文网首页iOS OCiOS技术专题
GCD之信号量dispatch_semaphore

GCD之信号量dispatch_semaphore

作者: ElaineYin | 来源:发表于2018-05-24 12:25 被阅读56次

    信号量是基于计数器的一种多线程同步机制,用来管理对资源的并发访问。
    信号量内部有一个可以原子递增或递减的值。如果一个动作尝试减少信号量的值,使其小于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系列

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

    相关文章

      网友评论

        本文标题:GCD之信号量dispatch_semaphore

        本文链接:https://www.haomeiwen.com/subject/fjxdjftx.html