GCD 信号量的理解与使用

引言:

信号量:就是一种可用来控制访问资源的数量的标识,设定了一个信号量,在线程访问之前,加上信号量的处理,则可告知系统按照我们指定的信号量数量来执行多个线程。

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


# 一. 三个函数

# 1. dispatch_semaphore_create

dispatch_semaphore_create(信号量值) 创建信号量

传入的参数为long,输出一个dispatch_semaphore_t类型且值为value的信号量。 值得注意的是,这里的传入的参数value必须大于或等于0,否则dispatch_semaphore_create会返回NULL。

# 2. dispatch_semaphore_signal

dispatch_semaphore_signal(信号量) 提高信号量

当返回值为0时表示当前并没有线程等待其处理的信号量,其处理的信号量的值加1即可。当返回值不为0时,表示其当前有(一个或多个)线程等待其处理的信号量,并且该函数唤醒了一个等待的线程(当线程有优先级时,唤醒优先级最高的线程;否则随机唤醒)。

# 3. dispatch_semaphore_wait

dispatch_semaphore_wait(信号量,等待时间) 这个函数会使传入的信号量dsema的值减1;

如果信号量的值 > 0,该函数所处线程就继续执行下面的语句,并且将信号量的值减1; 如果信号量的值 = 0,那么这个函数就阻塞当前线程等待 timeout(注意timeout的类型为dispatch_time_t,不能直接传入整形或float型数),如果等待的期间desema的值被dispatch_semaphore_signal函数加1了,且该函数(即dispatch_semaphore_wait)所处线程获得了信号量,那么就继续向下执行并将信号量减1。 如果等待期间没有获取到信号量或者信号量的值一直为0,那么等到timeout时,其所处线程自动执行其后语句。

在设置timeout时,比较有用的两个宏:DISPATCH_TIME_NOWDISPATCH_TIME_FOREVER

DISPATCH_TIME_NOW  // 表示当前;
DISPATCH_TIME_FOREVER // 表示遥远的未来;

# 二. 使用场景

在日常开发中经常会遇到 需要同时请求多个接口, 在多个接口同时请求完成时再做相关业务处理。

#pragma mark - 加载数据
- (void)loadDataSuccess:(void (^)(void))success
                failure:(void (^)(NSString *errorMessage))failure {
    
    // 3个接口,全部请求成功后刷新tableView
    NSInteger totalCount = 3;
    __block NSInteger requestCount = 0;
    
    //初始化一个信号量 值为0
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        /// 请求1
        // 请求成功时加入下面代码
        
        // 请求成功 requestCount+1 后 与 totalCount 比较 相等时 说明3个请求都已经完成, 信号量加1
        if (++requestCount == totalCount) {
            
            dispatch_semaphore_signal(sem); // 提高信号量  信号量加1
        }
        
        
        /// 请求2
        // 请求成功时加入下面代码
        if (++requestCount == totalCount) {
            dispatch_semaphore_signal(sem);
        }
        
        /// 请求3
        // 请求成功时加入下面代码
        if (++requestCount == totalCount) {
            dispatch_semaphore_signal(sem);
        }
        
        // 等待降低信号量
        // sem = 0 时,函数会阻塞当前线程 等待 timeout 后
        // sem > 0 时,该函数所处线程会继续执行下面语句,并将信号量减1
        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
        
        // 信号量大于0时 会执行下面代码
        dispatch_async(dispatch_get_main_queue(), ^{
            
            /// 所有请求完成
            // 实现回调
            success();
        });
    });
}