返回

多线程技术之 GCD 源码分析:栅栏函数、信号量揭秘

IOS

大家好,欢迎来到我们的 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 函数通过以下步骤创建一个屏障:

  1. 将屏障任务添加到队列中。
  2. 等待屏障任务完成执行。
  3. 允许屏障之后的任务开始执行。

异步和同步:

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。栅栏函数用于在并发队列中创建屏障,确保任务按照特定顺序执行。信号量用于控制对共享资源的访问,防止数据竞争。通过理解这些概念,我们可以编写出更健壮、更有效的并发代码。