如何在同一线程上调度异步以进行串行处理

Posted

技术标签:

【中文标题】如何在同一线程上调度异步以进行串行处理【英文标题】:How to dispatch async on the same thread for serial processing 【发布时间】:2013-12-15 19:18:52 【问题描述】:

当客户端收到推送通知时,我会运行一些冗长的同步任务。如果 2 个通知到达太快,我会在同步任务之间发生冲突,因为两者都尝试枚举和更改 coredata。

如何保留对队列的引用并将下一个同步任务分派到同一个队列?对这个问题表示歉意,但我的普通 C 语言不好。谢谢。

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // I would need to keep reference to 'queue' so I can dispatch to it again with next push notification

    dispatch_async(queue, ^

        [self.connection synchronizeWithLocal];

        dispatch_async(dispatch_get_main_queue(), ^
            // make UI updates
        );
    );

【问题讨论】:

【参考方案1】:

一个类可以有一个dispatch_queue_t 属性,就像任何其他属性一样。

@property (readwrite, assign) dispatch_queue_t myQueue;

只需像分配任何其他属性值一样分配队列。

self.myQueue = queue;

不过,您不希望在该代码中使用您正在使用的队列。 DISPATCH_QUEUE_PRIORITY_DEFAULT 是一个全局队列,也就是说

您无需将其保存在属性中,因为它始终存在(这就是函数名称中包含“全局”的原因)。 无论如何,您都不希望该队列用于您的目的,因为它是一个并发队列,因此它不会序列化操作。该队列非常适合并行运行多个操作,而这正是您想要避免的。

听起来您需要创建自己的串行队列。类似的东西

dispatch_queue_t queue = dispatch_queue_create("my queue", DISPATCH_QUEUE_SERIAL);

然后使用该队列而不是全局队列。完成后,请务必使用dispatch_release 进行清理。

【讨论】:

dispatch_release 在新版本的 ARC 下不需要(也不允许);该属性应该很强大。 @JesseRusak 同意,但从技术上讲,它不是“ARC 版本”或编译器版本的功能,而是取决于您应用的部署目标。如果部署目标小于 ios 6.0(或者如果您使用 -DOS_OBJECT_USE_OBJC=0 编译器标志),则需要 dispatch_release 我只针对 iOS7 并且显然使用了 ARC。所以我会相应地调整属性并跳过dispatch_release。感谢您的精彩回答。 感谢 Jesse 和 Rob 提供详细信息。【参考方案2】:

dispatch_get_global_queue() 给你一个并发调度队列。 如果你想要一个 serial 队列,你可以创建你自己的:

dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);

并存储它,例如在应用程序委托的属性中。

但是,如果这是为了进行 Core Data 操作,您最好创建一个 NSManagedObjectContextNSPrivateQueueConcurrencyType 并使用其 performBlock: 方法。

【讨论】:

以上是关于如何在同一线程上调度异步以进行串行处理的主要内容,如果未能解决你的问题,请参考以下文章

Java中的线程同步与异步如何理解?

iOS多线程——同步异步串行并行

ios多线程同步异步、串行并行队列、死锁

并发并行同步和异步

我可以假设计划在串行队列上运行的块都将在同一个线程上运行吗?

在windows处理器调度的过程中,线程的哪些状态可以转换到就绪状态