【发布时间】:2015-06-12 02:46:54
【问题描述】:
如何停止/取消/暂停/恢复 GCD 队列上的任务
如何一站式后台队列操作?我想在我们的应用程序中停止一些屏幕。有些屏幕应该是自动恢复的。那么,如何在 iOS 中传递队列呢?
我的意思是当用户浏览应用程序时,我们在 dispatch_queue_t 中运行后台线程。但它永远不会在代码中停止和恢复。那么如何暂停和恢复队列
【问题讨论】:
标签: ios queue grand-central-dispatch
如何停止/取消/暂停/恢复 GCD 队列上的任务
如何一站式后台队列操作?我想在我们的应用程序中停止一些屏幕。有些屏幕应该是自动恢复的。那么,如何在 iOS 中传递队列呢?
我的意思是当用户浏览应用程序时,我们在 dispatch_queue_t 中运行后台线程。但它永远不会在代码中停止和恢复。那么如何暂停和恢复队列
【问题讨论】:
标签: ios queue grand-central-dispatch
要挂起一个调度队列,只需queue.suspend()(Objective-C 中的dispatch_suspend(queue))。这不会影响当前正在运行的任何任务,而只会阻止新任务在该队列上启动。此外,您显然只挂起您创建的队列(不是全局队列,不是主队列)。
要恢复调度队列,它是queue.resume()(或Objective-C 中的dispatch_resume(queue))。没有“自动恢复”的概念,因此您只需要在适当的时候手动恢复即可。
要传递一个调度队列,您只需传递you created 的DispatchQueue 对象(或您在Objective-C 中调用dispatch_queue_create() 时创建的dispatch_queue_t 对象)。
在取消调度队列中排队的任务方面,这是在 iOS 8 中引入的。可以item.cancel() 和 DispatchWorkItem (dispatch_block_cancel(block) 在 Objective-C 中是 dispatch_block_t 对象)。这会取消尚未开始的排队块/项目,但不会停止正在进行的块/项目。如果您希望能够中断已调度的块/项目,则必须定期检查 item.isCancelled(或 Objective-C 中的 dispatch_block_testcancel())。
有关取消调度工作项的示例,请参阅https://stackoverflow.com/a/38372384/1271826。
如果你想取消任务,你也可以考虑使用操作队列,即OperationQueue(Objective-C 中的NSOperationQueue)。它的可取消操作已经存在了一段时间,您可能会在网上找到很多示例。它还支持使用maxConcurrentOperationCount 限制并发程度(而对于调度队列,您只能在串行和并发之间进行选择,而控制并发更多需要您付出一点点努力)。
如果使用操作队列,您可以通过更改队列的suspended 属性来暂停和恢复。要传递它,您只需传递您实例化的 NSOperationQueue 对象。
说了这么多,我建议您扩展您的问题,详细说明在后台运行的任务类型,并阐明您为什么要暂停它们。可能有比暂停后台队列更好的方法。
在您的 cmets 中,您提到您在 Swift 中使用 NSTimer,也就是 Timer。如果您想停止计时器,请致电timer.invalidate() 停止它。当你想重新启动它时,创建一个新的NSTimer。
或者如果计时器真的在后台线程上运行,GCD “调度源计时器”会更优雅地执行此操作。使用 GCD 计时器,您可以像暂停/恢复队列一样暂停/恢复它,只需使用计时器对象而不是队列对象。
【讨论】:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),然后在该块中有一个长时间运行的任务时,我如何暂停它,然后从另一个正在运行的任务中恢复它?或者GCD不可能吗?它们是 POSIX 线程,不是吗,那么 pthread_mutex_lock 等呢?
使用 GCD 队列时不能暂停/取消。如果您需要该功能(在很多一般情况下,即使您不需要),您应该使用更高级别的 API - NSOperationQueue。这是建立在 GCD 之上的,但它使您能够控制同时执行的事物数量、暂停队列处理以及取消单个/所有操作。
【讨论】:
NSOperationQueue 的建议,但在技术问题上,iOS 8 增加了 GCD 的取消功能。见Power, Performance and Diagnostics: What's new in GCD and XPC。
dispatch_cancel 很有用,但就像这些非垃圾收集平台上的所有其他取消习惯一样,它不能强制取消已经在运行的操作。它只能阻止一个块启动(即从队列中删除它)。如果您想在空中取消,您必须定期检查旗帜并提前返回。 NSOperation 通过提供标志在一定程度上对此有所帮助。强制取消没有灵丹妙药。