有没有办法实现dispatch_cancel()?

时间:2013-09-12 07:54:07

标签: ios grand-central-dispatch

到目前为止,我已经阅读了GCD的文档,但似乎错过了dispatch_cancel()我想用它来取消所有调度的块调用。 有没有办法实现dispatch_cancel()?

3 个答案:

答案 0 :(得分:10)

正如@HampusNilsson所提到的,你不能合理地取消任何在非垃圾收集环境(例如这个)中的飞行中操作,因为它本身会泄漏资源并使进程处于不确定状态。 NSOperationQueue具有取消API,并且该API可用于实现取消正在进行的操作,前提是操作本身正在协作检查该标志,然后提前清理并返回。这不是真正的,难以中止。

至于取消已入队但尚未开始的工作项,是的,NSOperationQueue处理此问题,但这需要额外的费用,NSOperationQueue是更高级别的抽象。 GCD的性能很大程度上取决于无锁队列的内部使用。无锁队列比基于锁的实现更快,但是为了达到这个速度,需要进行一些权衡。例如,我认为以无锁方式任意改变队列以删除已取消的操作会更加困难。我怀疑将公开的队列操作限制为“仅排队”,并使工作项本身不可变(块和函数ptrs),为许多优化提供了大门,这些优化允许GCD具有如此小的开销并且表现良好。 / p>

FWIW,在通常情况下,在现有的GCD API之上实现取消操作非常简单,因此任何需要此功能的人都可以很容易地自己完成(并且可能以更适合的方式)他们的具体需求比普通的API更好。考虑以下函数 - 它将队列上的一个块排队并返回一个块,您可以稍后调用它来取消排队操作:

dispatch_block_t dispatch_cancelable_async(dispatch_queue_t q, dispatch_block_t b)
{
    __block uintptr_t isCancelled = 0;
    dispatch_async(q, ^{
        if (!isCancelled) b();
    });
    return [[^{ isCancelled = 1; } copy] autorelease];
}

对于每种情况,这都不是正确的取消方法,但它是一个不错的第一近似值。

“使用最高级别的抽象来完成工作。”如果您想要取消,并且NSOperationQueue和GCD之间的开销差异不是一个重要因素,您应该只使用NSOperationQueue。有些人甚至认为在Objective-C中工作时使用NSOperationQueue是更惯用的选择。除此之外,如图所示,对GCD之上的常见情况实施非中止取消是相当微不足道的。

基于这一切,我怀疑在API的取消方面建立在性能和复杂性方面并不值得权衡。

答案 1 :(得分:1)

从iOS 8及更高版本,你可以用
取消块执行     dispatch_block_cancel

        SET @term = "someterm"
        SELECT DISTINCT
            posts.id,
            posts.post_author,
            posts.post_title, 
            posts.post_date, 
            LEFT(posts.post_content,300) post_content,
            wpmeta.meta_value thumbnail
        FROM wp_posts posts 
            INNER JOIN wp_postmeta wpm ON posts.id = wpm.post_id 
            INNER JOIN wp_postmeta wpmeta ON wpm.meta_value = wpmeta.post_id
            LEFT JOIN wp_term_relationships rel ON rel.object_id = posts.ID
            LEFT JOIN wp_term_taxonomy tax ON tax.term_taxonomy_id = rel.term_taxonomy_id
            LEFT JOIN wp_terms t ON t.term_id = tax.term_id
        WHERE 
            post_status = 'publish' 
            AND posts.post_type = 'post' 
            AND wpm.meta_key = '_thumbnail_id' 
            AND wpmeta.meta_key = '_wp_attached_file'
            AND 1 = 
                CASE
                    WHEN @term IS NULL THEN 1
                    WHEN @term IS NOT NULL AND t.term_id = @term THEN 1
                    ELSE 0
                END
        ORDER BY post_date DESC

答案 2 :(得分:0)

GCD没有实现取消API,因为它不安全(它可能在运行中中止线程)。如果你想取消任务,你需要自己动手,通过实现一个“已取消”的布尔值,并在它们开始时和之后定期检查你的任务。