dispatch queue.h

版本:iOS13.5

queue.h

dispatch其他文件通道

同步和异步的区别
当运行到dispatch_async时,会立即返回,继续执行下面的代码,而block会在队列queue中排队,轮到自己后执行。
当运行到dispatch_sync时,会先让block在队列queue中排队,轮到自己后执行,blcok里代码执行完毕后,才会返回,再继续执行下面的代码。
串行和并行的区别
串行时,block会在队列queue中排队,轮到自己后在队列queue开的线程(只有一个)中执行,若block是同步的,会先执行完block中的代码,再执行下一个block。若block是异步的,不管blcok中代码是否执行完,会继续执行下一个block。
并行时,block会在队列queue中排队,然后队列queue会为每一个block开一个线程,每一个block会在自己所属的线程中执行。

索引

  • 提交回调block到调度队列queue上并异步执行
    dispatch_async
  • 提交函数work到调度队列queue上并异步执行
    dispatch_async_f
  • 提交回调block到调度队列queue上并同步执行
    dispatch_sync
  • 提交函数work到调度队列queue上并同步执行
    dispatch_sync_f
  • 提交回调block到调度队列queue上并同步执行(会先等待queue中的异步block执行完成)
    dispatch_async_and_wait
  • 提交函数work到调度队列queue上并同步执行(会先等待queue中的异步block执行完成)
    dispatch_async_and_wait_f
  • 提交回调block到调度队列queue上并且并行调用。
    dispatch_apply
  • 提交函数work到调度队列queue上并且并行调用。
    dispatch_apply_f
  • 返回绑定到主线程的默认队列。
    dispatch_get_main_queue
  • 创建一个全局并发队列。
    dispatch_get_global_queue
  • 将调度队列属性值变成初始不活跃的属性值
    dispatch_queue_attr_make_initially_inactive
  • 为调度队列属性值设置自动释放频率frequency
    dispatch_queue_attr_make_with_autorelease_frequency
  • 为调度队列属性值设置QOS类qos_class和相对优先级relative_priority
    dispatch_queue_attr_make_with_qos_class
  • 创建一个新的调度队列
    dispatch_queue_create
  • 根据目标队列target创建一个新的调度队列。
    dispatch_queue_create_with_target
  • 返回队列的标签
    dispatch_queue_get_label
  • 返回队列的qos类和相对优先级
    dispatch_queue_get_qos_class
  • 为对象object设置目标队列。
    dispatch_set_target_queue
  • 执行提交到主队列的block(不要调用)
    dispatch_main
  • 安排一个block在指定时间when并在队列queue上执行
    dispatch_after
  • 安排一个函数work在指定时间when并在队列queue上执行。
    dispatch_after_f
  • 提交屏障block到调度队列queue上并异步执行。
    dispatch_barrier_async
  • 提交屏障函数work到调度队列queue上并异步执行。
    dispatch_barrier_async_f
  • 提交屏障block到调度队列queue上并同步执行。
    dispatch_barrier_sync
  • 提交屏障函数work到调度队列queue上并同步执行。
    dispatch_barrier_sync_f
  • 提交屏障block到调度队列queue上并同步执行。(会先等待queue中的异步项执行完成)
    dispatch_barrier_async_and_wait
  • 提交屏障函数work到调度队列queue上并同步执行。(会先等待queue中的异步项执行完成)
    dispatch_barrier_async_and_wait_f
  • 给调度队列queue设置对应键值key的上下文context。
    dispatch_queue_set_specific
  • 通过键值key获取调度队列queue的上下文context。
    dispatch_queue_get_specific
  • 通过对应键值key获取当前队列的上下文context。
    dispatch_get_specific
  • 验证当前的block是否在调度队列queue上执行。
    dispatch_assert_queue
  • 验证当前的block是否在调度队列queue上执行,并且将block充当队列queue上的屏障block。
    dispatch_assert_queue_barrier
  • 验证当前的block是否不在调度队列queue上执行。
    dispatch_assert_queue_not

详解

  • 提交回调block到调度队列queue上并异步执行
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

queue 要提交到的队列。系统将在队列上保留引用,直到block完成为止。
block 提交给队列的块

  • 提交函数work到调度队列queue上并异步执行
void dispatch_async_f(dispatch_queue_t queue,
        void *_Nullable context, dispatch_function_t work);

work 函数typedef void (*dispatch_function_t)(void *_Nullable);
context 函数work要传入的参数 是一个任意值的指针

例:
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"block");
    });
    int num = 2;
    dispatch_async_f(queue, &num, work);

void work(void *context) {
    NSLog(@"work");
}
输出:异步执行 顺序不定
block
work
或
work
block
  • 提交回调block到调度队列queue上并同步执行
void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

提交到队列的block在调用时不会遵守该队列的某些队列属性(例如自动释放频率dispatch_queue_attr_make_with_autorelease_frequency和QOS类qos_class_t)。
应注意死锁的问题。
参数说明见dispatch_async

  • 提交函数work到调度队列queue上并同步执行
void dispatch_sync_f(dispatch_queue_t queue, 
            void *_Nullable context, dispatch_function_t work);

参数说明见dispatch_async_f

例:
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(dispatch_get_main_queue(), ^{
        dispatch_sync(queue, ^{
            NSLog(@"sync_blcok");
            [NSThread sleepForTimeInterval:2];
        });
        dispatch_sync_f(queue, NULL, work);
    });

void work(void *context) {
    NSLog(@"work");
}
输出:
09:50:15.197956+0800 DEMO[43747:11194017] sync_blcok
09:50:17.199334+0800 DEMO[43747:11194017] work
  • 提交回调block到调度队列queue上并同步执行(会先等待queue中的异步block执行完成)
void dispatch_async_and_wait(dispatch_queue_t queue, dispatch_block_t block);

也会出现死锁的情况
dispatch_sync的不同点
提交到队列的block在调用时会遵守该队列的所有队列属性(例如自动释放频率和QOS类)。
当运行时调出一个线程来调用已经提交给队列的异步block时,该服务线程也将用于执行通过dispatch_async_and_wait提交给队列的同步block。
如果运行时没有该服务线程(因为它没有排队的block,或者只有同步block),则dispatch_async_and_wait将与dispatch_sync功能一致

例1:
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(dispatch_get_main_queue(), ^{
        if (@available(iOS 12.0, *)) {
            dispatch_async_and_wait(queue, ^{
                NSLog(@"wait1");
                [NSThread sleepForTimeInterval:2];
            });
            dispatch_async_and_wait(queue, ^{
                NSLog(@"wait2");
            });
        }
    });
输出:由于queue中没有异步工作项 所以效果与dispatch_sync一致
10:14:03.208297+0800 DEMO[44127:11218481] wait1
10:14:05.208632+0800 DEMO[44127:11218481] wait2
例2:
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(dispatch_get_main_queue(), ^{
        if (@available(iOS 12.0, *)) {
            dispatch_async_and_wait(queue, ^{
                NSLog(@"wait1");
                [NSThread sleepForTimeInterval:2];
            });
            dispatch_async_and_wait(queue, ^{
                NSLog(@"wait2");
            });
        }
    });
    dispatch_async(queue, ^{
        NSLog(@"async1");
        [NSThread sleepForTimeInterval:1];
    });
    dispatch_async(queue, ^{
        NSLog(@"async2");
        [NSThread sleepForTimeInterval:2];
    });
输出:queue中有异步工作项,所以会先等两个async执行完后 才会执行dispatch_async_and_wait
10:17:07.668667+0800 DEMO[44169:11221766] async1
10:17:08.671300+0800 DEMO[44169:11221766] async2
10:17:10.672588+0800 DEMO[44169:11221766] wait1
10:17:12.673911+0800 DEMO[44169:11221347] wait2
  • 提交函数work到调度队列queue上并同步执行(会先等待queue中的异步block执行完成)
void dispatch_async_and_wait_f(dispatch_queue_t queue,
        void *_Nullable context, dispatch_function_t work);

参数说明见dispatch_async_f

  • 提交回调block到调度队列queue上并且并行调用。
void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t));

该方法在返回之前等待全部block执行完成。如果队列是并发的,则可以同时调用block。
iterations 要执行的迭代次数
queue block要提交到的调度队列。传递的首选值是DISPATCH_APPLY_AUTO,以自动使用适合于调用线程的队列。
block void (^block)(size_t) 其中的size_t是当前迭代的索引

例1:
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"apply start");
        dispatch_apply(3, queue, ^(size_t index) {
            NSLog(@"start %ld", index);
            [NSThread sleepForTimeInterval:index+1];
            NSLog(@"end %ld", index);
        });
        NSLog(@"apply end");
    });
输出:因为queue是串行队列,所有每个block之间是排队串行执行的,并且全部block执行完成后,才会继续执行下面的代码。
10:39:19.035150+0800 DEMO[44455:11241456] apply start
10:39:19.035257+0800 DEMO[44455:11241456] start 0
10:39:20.035390+0800 DEMO[44455:11241456] end 0
10:39:20.035589+0800 DEMO[44455:11241456] start 1
10:39:22.035951+0800 DEMO[44455:11241456] end 1
10:39:22.036224+0800 DEMO[44455:11241456] start 2
10:39:25.037368+0800 DEMO[44455:11241456] end 2
10:39:25.037586+0800 DEMO[44455:11241456] apply end
例2:
将queue改成DISPATCH_APPLY_AUTO
输出:因为DISPATCH_APPLY_AUTO分配了一个并行队列,各个Block之间是并行执行的,待全部block执行完成后,才会继续执行下面的代码
10:46:27.792156+0800 DEMO[44525:11246686] apply start
10:46:27.792270+0800 DEMO[44525:11246686] start 0
10:46:27.792284+0800 DEMO[44525:11247284] start 1
10:46:27.792285+0800 DEMO[44525:11247279] start 2
10:46:28.793504+0800 DEMO[44525:11246686] end 0
10:46:29.792435+0800 DEMO[44525:11247284] end 1
10:46:30.793337+0800 DEMO[44525:11247279] end 2
10:46:30.793585+0800 DEMO[44525:11246686] apply end
  • 提交函数work到调度队列queue上并且并行调用。
void dispatch_apply_f(size_t iterations, dispatch_queue_t queue,
        void *_Nullable context, void (*work)(void *_Nullable, size_t));

work参数详情见dispatch_async_f

  • 返回绑定到主线程的默认队列。
dispatch_queue_main_t dispatch_get_main_queue(void);

主队列是绑定到应用程序主线程的串行队列。主队列是无法修改的,在主队列上调用dispatch_suspenddispatch_resumedispatch_set_context等将无效。
因为主队列的行为并不完全像常规的串行队列,所以在非UI应用程序(守护程序)的进程中使用时,主队列可能会产生有害的副作用。对于此类过程,应避免使用主队列。

  • 创建一个全局并发队列。
dispatch_queue_global_t dispatch_get_global_queue(long identifier, unsigned long flags);

全局并发队列在系统管理的线程池之上提供了优先级存储桶。系统将根据需求和系统负载来决定向该池分配多少个线程。特别是,系统尝试为此资源维护良好的并发级别,并且当太多现有工作线程在系统调用中阻塞时,系统将创建新线程。
全局并发队列是共享资源,因此,此资源的每个用户都有责任不向该池提交无限数量的工作,尤其是可能阻塞的工作,因为这可能导致系统产生非常大的数量线程数(又名线程爆炸)。
提交到全局并发队列的工作项是没有顺序保证的,并且工作项可以同时调用。
全局并发队列是无法修改的,在队列上调用dispatch_suspenddispatch_resumedispatch_set_context等将无效。

identifier qos_class_t表示服务质量等级 dispatch_queue_priority_t表示优先级。
qos_class_t 详细可查看dispatch block.hdispatch_block_create_with_qos_class方法
dispatch_queue_priority_t 优先级从上往下逐渐变低

//项目将以高优先级运行,即,将在任何默认优先级或低优先级队列之前执行。
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
//项目将以默认优先级运行
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
//调度到队列的项目将以低优先级运行
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
//调度到队列的项目将在后台优先级下运行
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
typedef long dispatch_queue_priority_t;

flags 保留以备将来使用。传递除0以外的任何值可能会导致返回NULL。

  • 将调度队列属性值变成初始不活跃的属性值
dispatch_queue_attr_t dispatch_queue_attr_make_initially_inactive(
        dispatch_queue_attr_t _Nullable attr);

调用dispatch_queue_create时传入不活跃的属性值时能使创建的队列初始不活跃,之后可以通过dispatch_activatedispatch_resume激活。
可以使用dispatch_set_target_queue更改处于不活跃队列的目标队列。一旦初始不活跃队列被激活,就不再允许更改目标队列。
必须先激活才能释放不活跃的队列。
attr 活跃的属性值

//用于创建调度队列的属性,该调度队列按FIFO顺序串行调用block。
#define DISPATCH_QUEUE_SERIAL NULL
//与DISPATCH_QUEUE_SERIAL相同,但是它是初始不活跃的。
#define DISPATCH_QUEUE_SERIAL_INACTIVE \
dispatch_queue_attr_make_initially_inactive(DISPATCH_QUEUE_SERIAL)
//用于创建调度队列的属性,该调度队列可同时调用block并使用提交给调度屏障API的屏障blcok
#define DISPATCH_QUEUE_CONCURRENT \
        DISPATCH_GLOBAL_OBJECT(dispatch_queue_attr_t, \
        _dispatch_queue_attr_concurrent)
//与DISPATCH_QUEUE_CONCURRENT相同,但是它是初始不活跃的。
#define DISPATCH_QUEUE_CONCURRENT_INACTIVE \
dispatch_queue_attr_make_initially_inactive(DISPATCH_QUEUE_CONCURRENT)

如上所示
DISPATCH_QUEUE_SERIAL_INACTIVE = dispatch_queue_attr_make_initially_inactive(DISPATCH_QUEUE_SERIAL)
DISPATCH_QUEUE_CONCURRENT_INACTIVE = dispatch_queue_attr_make_initially_inactive(DISPATCH_QUEUE_CONCURRENT)

  • 为调度队列属性值设置自动释放频率frequency
dispatch_queue_attr_t dispatch_queue_attr_make_with_autorelease_frequency(
        dispatch_queue_attr_t _Nullable attr, dispatch_autorelease_frequency_t frequency);

设置自动释放频率对同步提交到队列(dispatch_syncdispatch_barrier_sync)的block没有影响。
dispatch_get_global_queue创建的全局并发队列具有DISPATCH_AUTORELEASE_FREQUENCY_NEVER行为。
dispatch_queue_create手动创建的调度队列默认情况下使用DISPATCH_AUTORELEASE_FREQUENCY_INHERIT

frequency 自动释放频率

DISPATCH_ENUM(dispatch_autorelease_frequency, unsigned long,
//具有此自动释放频率的调度队列将从其目标队列继承全部行为。这是手动创建的队列的默认值。
    DISPATCH_AUTORELEASE_FREQUENCY_INHERIT  = 0,
//具有这种自动释放频率的调度队列会推送并弹出一个自动释放池去异步执行提交给它的每一个block
    DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM  = 1,
//具有这种自动释放频率的调度队列永远不会设置单个自动释放池去异步执行提交给它的block,这是全局并发队列的默认值。
    DISPATCH_AUTORELEASE_FREQUENCY_NEVER  = 2,
);
  • 为调度队列属性值设置QOS类qos_class和相对优先级relative_priority
dispatch_queue_attr_t
dispatch_queue_attr_make_with_qos_class(dispatch_queue_attr_t _Nullable attr,
        dispatch_qos_class_t qos_class, int relative_priority);

当以这种方式设置时,QOS类和相对优先级优先于从调度队列的目标队列dispatch_set_target_queue继承的优先级
qos_class 详情见dispatch_get_global_queue
relative_priority QOS类中的相对优先级。该值是与最大支持的调度程序优先级的负偏移量。传递大于0或小于QOS_MIN_RELATIVE_PRIORITY的值将导致返回NULL。
#define QOS_MIN_RELATIVE_PRIORITY (-15)

例:
    //将DISPATCH_QUEUE_SERIAL变成非活跃的DISPATCH_QUEUE_SERIAL_INACTIVE
    dispatch_queue_attr_t attr = dispatch_queue_attr_make_initially_inactive(DISPATCH_QUEUE_SERIAL);
    //设置频率
    attr = dispatch_queue_attr_make_with_autorelease_frequency(attr, DISPATCH_AUTORELEASE_FREQUENCY_INHERIT);
    //设置qos类
    attr = dispatch_queue_attr_make_with_qos_class(attr, QOS_CLASS_DEFAULT, 0);
    //创建串行队列
    dispatch_queue_t attr_queue = dispatch_queue_create("attr_queue", attr);
    //激活队列 因为DISPATCH_QUEUE_SERIAL_INACTIVE是不活跃的
    dispatch_activate(attr_queue);
  • 创建一个新的调度队列
dispatch_queue_t dispatch_queue_create(const char *_Nullable label,
        dispatch_queue_attr_t _Nullable attr);

label 附加到队列的字符串。此参数可以为NULL。
attr 属性值 DISPATCH_QUEUE_SERIAL串行 DISPATCH_QUEUE_CONCURRENT并行
可以通过dispatch_queue_attr_make_initially_inactive设置队列的活跃状态
可以通过dispatch_queue_attr_make_with_autorelease_frequency设置队列的自动释放频率
可以通过dispatch_queue_attr_make_with_qos_class设置队列的qos类和相对优先级

  • 根据目标队列target创建一个新的调度队列。
dispatch_queue_t dispatch_queue_create_with_target(const char *_Nullable label,
        dispatch_queue_attr_t _Nullable attr, dispatch_queue_t _Nullable target);

此方式创建的队列不能更改其目标队列dispatch_set_target_queue,除非创建的队列处于非活动状态,才可以更改目标队列,直到使用dispatch_activate激活为止。
target 目标队列 目标队列会被保留。如果此参数是DISPATCH_TARGET_QUEUE_DEFAULT,则将队列的目标队列设置为指定队列类型的默认目标队列。
#define DISPATCH_TARGET_QUEUE_DEFAULT NULL

例:
    dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue2 = dispatch_queue_create_with_target("queue2", DISPATCH_QUEUE_CONCURRENT, queue1);
    dispatch_queue_t queue3 = dispatch_queue_create_with_target("queue3", DISPATCH_QUEUE_SERIAL, DISPATCH_TARGET_QUEUE_DEFAULT);
  • 返回队列的标签
const char * dispatch_queue_get_label(dispatch_queue_t _Nullable queue);

若创建时为标签为NULL,则返回空字符串。
queue 队列 若为DISPATCH_CURRENT_QUEUE_LABEL将返回当前队列的标签
#define DISPATCH_CURRENT_QUEUE_LABEL NULL

  • 返回队列的qos类和相对优先级
dispatch_qos_class_t dispatch_queue_get_qos_class(dispatch_queue_t queue,
        int *_Nullable relative_priority_ptr);

relative_priority_ptr 相对优先级的指针
如果队列是dispatch_queue_attr_make_with_qos_class返回的属性值创建的,则此函数返回的QOS类和相对优先级;否则它将返回QOS_CLASS_UNSPECIFIED的QOS类和相对优先级0。
如果队列是全局并发队列,则此函数返回在dispatch_get_global_queue下记录的已分配QOS类和相对优先级0;否则,返回0。
如果队列是主队列dispatch_get_main_queue,它将返回由qos_class_main提供的QOS值和相对优先级0。

例:
    dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0);
    dispatch_queue_t attr_queue = dispatch_queue_create("attr_queue", attr);
    const char *name = dispatch_queue_get_label(attr_queue);
    int priority = -10;
    dispatch_qos_class_t qos = dispatch_queue_get_qos_class(attr_queue, &priority);
    NSLog(@"%s %u %d", name, qos, priority);
输出:
attr_queue 21 0
  • 为对象object设置目标队列。
void dispatch_set_target_queue(dispatch_object_t object,dispatch_queue_t _Nullable queue);

如果object在创建时没有设置某些属性(服务质量等级和相对优先级等),则object将从其目标队列queue继承这些属性。
通常,更改object的目标队列是异步操作,该操作不会立即生效,也不会影响已经与object关联的block。
但是,如果在调用该方法时object处于非活动状态,则目标队列queue更改将立即生效,并将影响已经与object关联的block。
设置目标队列后object的block将会被目标队列管理
object 对象 dispatch_queue_tdispatch_source_t都可以当做dispatch_object_t使用
queue 对象object的新目标队列。会保留队列,并释放先前的目标队列(如果有)。如果queue是DISPATCH_TARGET_QUEUE_DEFAULT,则将为对象object设置指定对象类型的默认目标队列。

例:
    dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue3 = dispatch_queue_create("queue3", DISPATCH_QUEUE_CONCURRENT);
    
//    dispatch_queue_t queue4 = dispatch_queue_create("queue4", DISPATCH_QUEUE_SERIAL);
//    dispatch_set_target_queue(queue1, queue4);
//    dispatch_set_target_queue(queue2, queue4);
//    dispatch_set_target_queue(queue3, queue4);

    dispatch_async(queue1, ^{
        NSLog(@"queue1");
    });
    dispatch_async(queue2, ^{
        NSLog(@"queue2");
    });
    dispatch_async(queue3, ^{
        NSLog(@"queue3_1 start");
        [NSThread sleepForTimeInterval:2];
        NSLog(@"queue3_1 end");
    });
    dispatch_async(queue3, ^{
        NSLog(@"queue3_2 start");
        [NSThread sleepForTimeInterval:1];
        NSLog(@"queue3_2 end");
    });
输出:queue1 queue2 queue3_1 start queue3_2 start这4项是同时乱序输出的,1秒后输出queue3_2 end 再1秒后输出queue3_1 end 
16:31:25.040349+0800 DEMO[47673:11436311] queue3_2 start
16:31:25.040351+0800 DEMO[47673:11436310] queue2
16:31:25.040352+0800 DEMO[47673:11436322] queue3_1 start
16:31:25.040348+0800 DEMO[47673:11436316] queue1
16:31:26.044913+0800 DEMO[47673:11436311] queue3_2 end
16:31:27.045366+0800 DEMO[47673:11436322] queue3_1 end
若取消上面的注释
则输出: 可以看出所有异步执行都变成了串行执行,即使queue3是并发的,也变成了串行执行,是因为所有的队列都被queue4重新管理了,而queue4是串行的。
16:34:11.166613+0800 DEMO[47708:11438765] queue1
16:34:11.166768+0800 DEMO[47708:11438765] queue2
16:34:11.166896+0800 DEMO[47708:11438765] queue3_1 start
16:34:13.170399+0800 DEMO[47708:11438765] queue3_1 end
16:34:13.170603+0800 DEMO[47708:11438765] queue3_2 start
16:34:14.174332+0800 DEMO[47708:11438765] queue3_2 end
  • 执行提交到主队列的block(不要调用)
void dispatch_main(void);

此方法“驻留”主线程,并等待block提交到主队列。
该函数永不返回,所以不要调用,不然会一直堵塞当前线程。

  • 安排一个block在指定时间when并在队列queue上执行。
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue,
                dispatch_block_t block);

when 传入DISPATCH_TIME_NOW表示立即执行 传入DISPATCH_TIME_FOREVER表示永不执行
传入dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC)表示延时1秒钟执行

  • 安排一个函数work在指定时间when并在队列queue上执行。
void dispatch_after_f(dispatch_time_t when, dispatch_queue_t queue,
        void *_Nullable context, dispatch_function_t work);

work 参数说明见dispatch_async_f

例:
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //1秒钟后执行block
    });
  • 提交屏障block到调度队列queue上并异步执行。
void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);

屏障块仅在​​使用DISPATCH_QUEUE_CONCURRENT属性创建的队列时才有特殊的效果;在这样的队列上,屏障block将不会运行,直到所有较早提交给队列的block都已完成;屏障block之后提交给队列的block也都不会运行,直到屏障block完成。
当提交到全局队列dispatch_get_global_queue或未使用DISPATCH_QUEUE_CONCURRENT属性创建的队列时,该方法作用与dispatch_asyncdispatch_sync相同。

  • 提交屏障函数work到调度队列queue上并异步执行。
void dispatch_barrier_async_f(dispatch_queue_t queue,
        void *_Nullable context, dispatch_function_t work);

work 参数说明见dispatch_async_f

  • 提交屏障block到调度队列queue上并同步执行。
void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);
  • 提交屏障函数work到调度队列queue上并同步执行。
void dispatch_barrier_sync_f(dispatch_queue_t queue, void *_Nullable context, 
                      dispatch_function_t work);

work 参数说明见dispatch_async_f

例:
    dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue1, ^{
        NSLog(@"1");
    });
    dispatch_async(queue1, ^{
        NSLog(@"2");
    });
    dispatch_async(queue1, ^{
        NSLog(@"3");
    });
    dispatch_barrier_async(queue1, ^{
        NSLog(@"barrier");
    });
    dispatch_async(queue1, ^{
        NSLog(@"4");
    });
    dispatch_async(queue1, ^{
        NSLog(@"5");
    });
输出:其中前3个block是乱序 等前3个完成后执行屏障block 屏障block完成后 乱序执行后两个block
1
3
2
barrier
5
4
  • 提交屏障block到调度队列queue上并同步执行。(会先等待queue中的异步项执行完成)
void dispatch_barrier_async_and_wait(dispatch_queue_t queue, dispatch_block_t block);

只对用DISPATCH_QUEUE_CONCURRENT创建的队列有作用,否则与dispatch_async_and_wait效果相同。
因为dispatch_barrier_async_and_wait中的async_and_wait的作用是等待队列中async的block执行完成,dispatch_barrier_async_and_wait中的barrier作用是等待之前所有blcok执行,所以dispatch_barrier_async_and_wait的功能为等待所有同步或异步的block都执行完成。

  • 提交屏障函数work到调度队列queue上并同步执行。(会先等待queue中的异步项执行完成)
void dispatch_barrier_async_and_wait_f(dispatch_queue_t queue,
        void *_Nullable context, dispatch_function_t work);

只对用DISPATCH_QUEUE_CONCURRENT创建的队列有作用,否则与dispatch_async_and_wait_f效果相同。

  • 给调度队列queue设置对应键值key的上下文context。
void dispatch_queue_set_specific(dispatch_queue_t queue, const void *key,
        void *_Nullable context, dispatch_function_t _Nullable destructor);

当为同一key设置新上下文context时,或者在释放对队列的所有引用之后,将使用默认优先级全局并发队列dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)上的上下文并调用函数destructor。
key 设置上下文的键值

  • 通过键值key获取调度队列queue的上下文context。
void *_Nullable dispatch_queue_get_specific(dispatch_queue_t queue, const void *key);

key 获取上下文的键值

  • 通过对应键值key获取当前队列的上下文context。
void *_Nullable dispatch_get_specific(const void *key);

key 获取上下文的键值

例:
    dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
    int context = 10;
    dispatch_queue_set_specific(queue1, "key", &context, work);
    int context1 = 11;
    dispatch_queue_set_specific(queue1, "key1", &context1, work);
    int *adress1 = dispatch_queue_get_specific(queue1, "key");
    int *adress2 = dispatch_queue_get_specific(queue1, "key1");
    NSLog(@"%d %d", *adress1, *adress2);
    dispatch_sync(queue1, ^{
        int *adress1 = dispatch_get_specific("key");
        int *adress2 = dispatch_get_specific("key1");
        NSLog(@"%d %d", *adress1, *adress2);
    });
    dispatch_async(queue1, ^{
        int *adress1 = dispatch_get_specific("key");
        int *adress2 = dispatch_get_specific("key1");
        NSLog(@"%d %d", *adress1, *adress2);
    });

void work(void *context) {

}
输出:可以看出dispatch_sync同步时获取的context是相同的,而异步时却不同,不知为何。
10 11
10 11
0 0
例:
    const void *key = "key";
    dispatch_queue_t queue1 = dispatch_queue_create(key, DISPATCH_QUEUE_SERIAL);
    dispatch_queue_set_specific(queue1, key, &key, NULL);
    dispatch_async(queue1, ^{
        if (dispatch_get_specific(key)) {
            NSLog(@"当前的队列是queue1");
        } else{
            NSLog(@"当前的队列不是queue1");
        }
    });
输出:可通过该方式判断当前队列
当前的队列是queue1
  • 验证当前的block是否在调度队列queue上执行。
void dispatch_assert_queue(dispatch_queue_t queue);

如果当前正在执行的block已提交到队列queue或任何以它为目标的队列dispatch_set_target_queue,则此函数返回,代码继续运行。否则,该方法会触发断定NSAssert。
该方法请仅在调试中使用。

  • 验证当前的block是否在调度队列queue上执行,并且将block充当队列queue上的屏障block。
void dispatch_assert_queue_barrier(dispatch_queue_t queue);

屏障的作用详见dispatch_barrier_async

  • 验证当前的block是否不在调度队列queue上执行。
void dispatch_assert_queue_not(dispatch_queue_t queue)

dispatch_assert_queue功能相反

例:
dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue1, ^{
        NSLog(@"1");
        dispatch_assert_queue(queue1);
        NSLog(@"2");
        [NSThread sleepForTimeInterval:1];
    });
    dispatch_assert_queue(dispatch_get_main_queue());
    dispatch_assert_queue_not(queue1);
    NSLog(@"3");
输出:
3
1
2
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339