您的位置:首页 > 其它

GCD高级用法-信号量

2015-05-22 11:25 543 查看
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);
});
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息