暂停串行队列

时间:2016-10-21 20:07:46

标签: ios objective-c grand-central-dispatch

今天我尝试了以下代码:

- (void)suspendTest {
    dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_BACKGROUND, 0);
    dispatch_queue_t suspendableQueue = dispatch_queue_create("test", attr);
    for (int i = 0; i <= 10000; i++) {
        dispatch_async(suspendableQueue, ^{
            NSLog(@"%d", i);
        });
        if (i == 5000) {
            dispatch_suspend(suspendableQueue);
        }
    }
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"Show must go on!");
        dispatch_resume(suspendableQueue);
    });
}

代码启动10001个任务,但它应该暂停队列中途运行新任务,以便在6秒内恢复。并且此代码按预期工作 - 执行5000个任务,然后队列停止,并在6秒后恢复。 但是如果我使用串行队列而不是并发队列,那么我的行为就不清楚了。

dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_BACKGROUND, 0);

在这种情况下,随机数量的任务设法在挂起之前执行,但通常这个数字接近于零(暂停发生在任何任务之前)。 问题是 - 为什么挂起对串行和并发队列的工作方式不同以及如何正确挂起串行队列?

2 个答案:

答案 0 :(得分:1)

根据其名称,串行队列执行串行任务,即仅在完成上一个任务之后从下一个开始。优先级是后台,因此当前队列到达第5000个任务并挂起队列时,它甚至可能都没有在第一个任务上启动。

来自dispatch_suspend的文档:

  

在完成呼叫时运行的任何阻止后,将暂停。

,即它承诺队列上的异步调度任务完成,只有任何当前正在运行的任务(块)不会在中途暂停。在串行队列上,最多一个任务可以是“当前正在运行”,而在并发队列上没有指定的上限。 编辑:根据您的测试,有一百万个任务,似乎并发队列维护概念抽象,它是“完全并发”的,因此即使它们实际上也认为它们都“正在运行”不是

要在第5000个任务之后暂停它,您可以从第5000个任务本身触发它。 (那么你可能也希望从暂停时开始执行resume-timer,否则理论上如果简历在暂停之前就不会恢复。)

答案 1 :(得分:1)

我认为问题在于您将suspendbarrier混淆。 suspend阻止队列现在。屏障执行前队列中的所有内容都会停止barrier。因此,如果您在第5000个任务之后放置障碍,则在我们暂停在串行队列的屏障之前将执行5000个任务。