多线程技术之 GCD 源码分析:栅栏函数、信号量揭秘
2024-01-09 09:43:06
大家好,欢迎来到我们的 iOS 底层原理探究系列。在上一篇文章中,我们深入剖析了 GCD 的串行队列和并发队列。今天,我们将继续深入 GCD 的源码,探究栅栏函数 dispatch_barrier_(a)sync
和信号量 dispatch_semaphore
。
栅栏函数 dispatch_barrier_(a)sync
dispatch_barrier_(a)sync
函数是一种特殊的同步函数,它用于在并发队列中创建屏障,确保在屏障之前执行的任务全部完成之后,才能执行屏障之后的任务。
语法:
void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);
参数:
queue
:目标并发队列。block
:需要在屏障之前或之后执行的任务。
工作原理:
dispatch_barrier_(a)sync
函数通过以下步骤创建一个屏障:
- 将屏障任务添加到队列中。
- 等待屏障任务完成执行。
- 允许屏障之后的任务开始执行。
异步和同步:
dispatch_barrier_async
以异步方式创建屏障,这意味着屏障任务会在后台执行,而不会阻塞主线程。dispatch_barrier_sync
以同步方式创建屏障,这意味着屏障任务将在当前线程中执行,并且会在屏障之后的任务开始执行之前阻塞主线程。
示例:
以下代码创建一个并发队列并使用 dispatch_barrier_async
函数创建屏障:
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.example.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_barrier_async(concurrentQueue, ^{
// 屏障之前执行的任务
});
dispatch_async(concurrentQueue, ^{
// 屏障之后的任务
});
注意:
- 屏障函数只能用于并发队列。
- 屏障任务必须是最后一个添加到队列中的任务,否则屏障将不起作用。
dispatch_barrier_async
函数不会阻塞主线程,而dispatch_barrier_sync
函数会阻塞主线程。
信号量 dispatch_semaphore
dispatch_semaphore
是一种同步机制,它用于控制对共享资源的访问。信号量可以初始化为 0 或大于 0 的值,表示资源的可用数量。
语法:
dispatch_semaphore_t dispatch_semaphore_create(long value);
long dispatch_semaphore_wait(dispatch_semaphore_t semaphore, dispatch_time_t timeout);
long dispatch_semaphore_signal(dispatch_semaphore_t semaphore);
参数:
value
:信号量的初始值。semaphore
:目标信号量。timeout
:等待信号量的超时时间。
工作原理:
初始化:
dispatch_semaphore_create
函数初始化一个信号量,并将其初始值设置为 value
。
等待:
dispatch_semaphore_wait
函数尝试获取信号量。如果信号量不可用(值为 0),该函数将阻塞当前线程,直到信号量变为可用或达到超时时间。如果在超时时间内信号量仍不可用,该函数将返回 -1
。
释放:
dispatch_semaphore_signal
函数释放信号量,将信号量值增加 1。如果等待信号量的线程存在,则该线程将被唤醒。
示例:
以下代码创建一个信号量并使用它来控制对共享资源的访问:
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 获取信号量
long result = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// 访问共享资源
// ...
// 释放信号量
dispatch_semaphore_signal(semaphore);
});
注意:
- 信号量可以用于任何类型的共享资源,例如数据结构、文件或网络连接。
- 信号量可以防止多个线程同时访问共享资源,从而避免数据竞争。
dispatch_semaphore_wait
函数可以指定超时时间,以防止线程无限期地阻塞。
总结
在本篇文章中,我们深入探讨了 GCD 中的栅栏函数 dispatch_barrier_(a)sync
和信号量 dispatch_semaphore
。栅栏函数用于在并发队列中创建屏障,确保任务按照特定顺序执行。信号量用于控制对共享资源的访问,防止数据竞争。通过理解这些概念,我们可以编写出更健壮、更有效的并发代码。