通常遇到多个线程访问同一块内存空间,我们会用同步队列处理(Serial Dispatch Queue)或者在异步队列中根据栅栏函数(dispatch_barrier_async)来避免数据竞争。
但是当我们用栅栏函数的时候,会发现用这两种方法,执行的效率并不高,并不能完全体现出多线程的有点,所以如果考虑到更细粒度的排他控制,我们可以用Dispatch_Semaphore来操作。
1.应用函数dispatch_semaphore_create来进行创建:
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
2.等待函数:dispatch_semaphore_wait
//第二个函数是dispatch_time_t 类型的时间,这里是永久等待
long result = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//可以安全的执行排他控制的处理
if(result ==0) {
//由于dispatch_semaphore 的计数值大于等于1
//或者在待机中的指定时间
//dispatch_semaphore的计数值减去1
//执行需要进行排他控制的处理
}else{
//dispatch_semaphore 计数值为 0
//达到指定时间为止待机
}
3.信号的引用计数加1函数:dispatch_semaphore_signal
dispatch_semaphore_signal(semaphore);
举一个例子:
当我们创建了一个NSMutableArray,想要用多线程往数组里添加不同的数值,假设是1000组数据(显然这里不可能开1000个线程,我们现在只是考虑粒度的问题,暂不考虑开多少线程的问题),并且如果使用了多线程,那么肯定是需要添加防止数据竞争的操作来防止内存的错误,现在用更细粒度的排他控制来添加。
上代码:
//所以源代码中使用dispatch_semaphore
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//生成dispatch_semaphore,并且默认值计数值为1
dispatch_semaphore_t semaphore1 = dispatch_semaphore_create(1);
NSMutableArray *array = [[NSMutableArray alloc] init];
for(inti =0; i <1000; i ++ ) {
dispatch_async(queue, ^{
//等待dispatch_semaphore 直到计数值大于或者等于1.
dispatch_semaphore_wait(semaphore1, DISPATCH_TIME_FOREVER);
//1.由于dispatch_semaphore 计数值 >= 1
//2.所以将计数值减去1,并且dispatch_semaphore_wait执行回掉
//3.计数值为“0”。
//4.由于访问NSMutableArray 类对象的线程只有1个,因此可以安全的访问内存空间
[arrayaddObject:[NSNumber numberWithInt:i]];
//1.排他控制结束,需要对dispatch_semaphore计数进行加1
//2.通过dispatch_semaphore_wait函数等待dispatch_semaphore的计数值增加的线程,有最先等待的线程执行。
dispatch_semaphore_signal(semaphore1);
});
}
网友评论