GCD中的dispatch_semaphore的语法与作用
(一)引入问题
当并行执行的处理更新数据时,会产生数据不一致的情况,有时应用程序还会异常结束,虽然使用Serial Dipatch queue和dispatch_barrier_async函数可避免这类问题,但有必要进行更加细腻的排他控制
1 /*! 2 * @brief 不考虑顺序,将所有数据添加到数组中 3 */ 4 - (void)testError { 5 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 6 7 NSMutableArray *mArray = [NSMutableArray array]; 8 //当执行次数过大时,异常结束的概率很高 9 for (int i = 0; i < 10000; i++) { 10 11 dispatch_async(queue, ^{ 12 13 [mArray addObject:[NSNumber numberWithInt:i]]; 14 }); 15 } 16 NSLog(@"%@", mArray); 17 /*! 18 * @brief 运行结果 19 *semaphore测试(3312,0x11ab21000) malloc: *** error for object 0x7f971c047000: pointer being freed was not allocated 20 *** set a breakpoint in malloc_error_break to debug 21 * @return 异常结束 22 */ 23 }
(二)什么是dispatch_semaphore
dispatch_semaphore是持有计数的信号,该计数是多线程编程中的计数类型信号,类似于过马路的信号灯,红灯表示不能通过,而绿灯表示可以通过
而在dispatch_semaphore中使用计数来实现该功能,进行更细粒度的排他控制.
在没有Serial Dispatch Queue和dispatch_barrier_async函数那么大的粒度且一部分处理需要进行排他控制的情况下,dispatch Semaphore便可发挥威力
(三)dispatch_semaphore语法说明
<1>通过dispatch_semaphore_create(long value);函数创建Dispatch_Semaphore,参数表示计数的初始值
//参数说明
//long value:表示计数的初始值
dispatch_semaphore_t semaphore = dispatch_semaphore_create(long value);
<2>dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);函数等待Dispatch Semaphore的计数值大于或者等于1,当满足条件时计数器执行减法,并从wait函数中返回
***当dispatch_semaphore_wait函数返回0时,可以安全地执行排他控制的处理
//参数说明
//dispatch_semaphore_t dsema:操作的Dispatch_Semaphore对象
//dispatch_time_t timeout:由dispatch_time_t类型值指定等待时间
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
<3>dispatch_semaphore_signal(dispatch_semaphore_t dsema);函数将Dispatch_Semaphore的计数器加1
//参数说明
//dispatch_semaphore_t dsema:操作的Dispatch_Semaphore对象
dispatch_semaphore_signal(dispatch_semaphore_t dsema);
(三)代码演示
1 /*! 2 * @brief 使用Dispatch Semaphore进行排他性控制 3 */ 4 - (void)semaphoreSample { 5 //1.创建全局队列 6 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 7 //2.创建dispatch_semaphore_t对象 8 dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); 9 //3.创建保存数据的可变数组 10 NSMutableArray *mArray = [NSMutableArray array]; 11 //执行10000次操作 12 for (int i = 0; i < 10000; i++) { 13 //异步添加数据 14 dispatch_async(queue, ^{ 15 //数据进入,等待处理,信号量减1 16 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 17 //处理数据 18 [mArray addObject:[NSNumber numberWithInt:i]]; 19 //数据处理完毕,信号量加1,等待下一次处理 20 dispatch_semaphore_signal(semaphore); 21 }); 22 } 23 24 NSLog(@"%@", mArray); 25 26 /*! 27 * @brief 执行结果 28 * 29 1 30 2 31 3 32 ... 33 9999 34 * @return 顺序输出,不会异常结束 35 */ 36 }