GCD高级用法-信号量

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014205965/article/details/45915135

GCD中的信号量是指 Dispatch Semaphore。

所谓信号,类似于道路上的信号灯,一种用来标识等待还是通过的标志。绿灯通过,红灯等待。道路中通过信号灯的颜色标识通过和等待,而Dispatch Semaphore中通过“计数”来标识通过和等待。

GCD的Dispatch Semaphore提供了三个函数操作Semaphore
  
dispatch_semaphore_create  //创建一个semaphore
dispatch_semaphore_signal //发送一个信号
dispatch_semaphore_wait  //等待信号
    
    /*
     通过dispatch_semaphore_create 函数创建一个Semaphore并初始化信号的总量。
     通过dispatch_semaphore_signal 函数发送一个信号,让信号总量加1。
     通过dispatch_semaphore_wait可以使总信号量减1,当信号总量为0时就会一直等待,否则就可以正常执行
     */

接下来详细说明一下这3个函数:
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
通过dispatch_semaphore_create 函数生成Dispatch Semaphore。参数表示计数的初始值,上面设置的初始值为1。

long dispatch_semaphore_wait(dispatch_semaphore_t semaphore, dispatch_time_t timeout);

如果此时semaphore信号量的值 >= 1时:对semaphore计数进行减1,然后dispatch_semaphore_wait 函数返回。该函数所处线程就继续执行下面的语句。
如果此时semaphore信号量的值 = 0时:那么就阻塞该函数所处的线程,阻塞时长为timeout指定的时间,如果阻塞时间内semaphore的值被dispatch_semaphore_signal函数加1了,该函数所处线程获得了信号量被唤醒。然后对semaphore计数进行减1并返回,继续向下执行。如果阻塞时间内没有获取到信号量唤醒线程或者信号量的值一直为0,那么就要等到指定的阻塞时间后,该函数所处线程才继续向下执行。

dispatch_semaphore_wait 函数返回值为long类型;
返回值为0时:说明semaphore的值大于等于1,或者在timeout指定时间之内,该函数所处的线程被成功唤醒(比如通过dispatch_semaphore_signal将线程唤醒)。
返回值不为0时:说明semaphore的值等于0,此时timeout指定时间内该函数所处的线程处于阻塞。
另外,dispatch_semaphore_wait 函数的返回值也dispatch_group_wait 函数相同,可以通过返回值可以进行分支处理。

dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);

long result = dispatch_semaphore_wait(semaphore, 1ull * NSEC_PER_SEC);

if (result == 0) {
    /* 返回0时,可安全地执行需要进行排他控制的处理。该处理结束后通过dispatch_semaphore_signal 函数将Dispatch Semaphore 的计数值加1. */

}else{
   /* 说明semaphore的值等于0,此时timeout指定时间内该函数所处的线程处于阻塞 */

}

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

通过下面案例,看看Dispatch Semaphore的几个函数在实际开发中的应用:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    
    NSMutableArray *array = [[NSMutableArray alloc]init];
    for (NSInteger i = 0; i < 100000; i++) {
        dispatch_async(queue, ^{
            /*
             此时semaphore信号量的值如果 >= 1时:对semaphore计数进行减1,然后dispatch_semaphore_wait 函数返回。该函数所处线程就继续执行下面的语句。
             
             此时semaphore信号量的值如果=0:那么就阻塞该函数所处的线程,阻塞时长为timeout指定的时间,如果阻塞时间内semaphore的值被dispatch_semaphore_signal函数加1了,该函数所处线程获得了信号量被唤醒。然后对semaphore计数进行减1并返回,继续向下执行。 如果阻塞时间内没有获取到信号量唤醒线程或者信号量的值一直为0,那么就要等到指定的阻塞时间后,该函数所处线程才继续向下执行。
             
             执行到这里semaphore的值总是1
             */
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            
            /* 因为dispatch_semaphore_create创建的semaphore的初始值为1,执行完上面的
             dispatch_semaphore_wait函数之后,semaphore计数值减1会变为0,所以可访问array对象的线程只有1个,因此可安全地对array进行操作。
             */
            [array addObject:[NSNumber numberWithInteger:i]];
            
            /*
             对array操作之后,通过dispatch_semaphore_signal将semaphore的计数值加1,此时semaphore的值由变成了1,所处
             */
            dispatch_semaphore_signal(semaphore);
        });
    }
}




猜你喜欢

转载自blog.csdn.net/u014205965/article/details/45915135