调度队列:如何判断它们是否正在运行以及如何阻止它们 [英] Dispatch queues: How to tell if they're running and how to stop them

查看:116
本文介绍了调度队列:如何判断它们是否正在运行以及如何阻止它们的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



这里是翻转硬币的方法:

   - (void)flipCoins:(NSUInteger)nFlips {

//为工作创建队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,NULL);

//将翻转次数分成kchunkSize和其余部分的整个块。
NSUInteger numberOfWholeChunks = nFlips / kChunkSize;
NSUInteger numberOfRemainingFlips = nFlips - numberOfWholeChunks * kChunkSize;

if(numberOfWholeChunks> 0){
for(NSUInteger index = 0; index< numberOfWholeChunks; index ++){
dispatch_async(queue,^ {
NSUInteger h = 0;
NSUInteger t = 0;
flipTheCoins(kChunkSize,& h,& t);
dispatch_async(mainQueue,^ {
self.nHeads + = h ;
self.nTails + = t;
});
});
}
}
if(numberOfRemainingFlips> 0){
dispatch_async(queue,^ {
NSUInteger h = 0;
NSUInteger t = 0;
flipTheCoins(numberOfRemainingFlips,& h,& t);
dispatch_async(mainQueue,^ {
self.nHeads + = h;
self.nTails + = t;
});
});

}
}

我打破翻转的数量大块,在后台翻转他们和更新主队列中的属性。窗口控制器正在观察属性,并使用运行结果更新UI。



我浏览了并发编程指南和GCD文档,虽然有一种方法可以暂停一个队列,没有办法阻止它们,并删除所有排队的和没有运行的对象。



我想能够连接一个停止按钮,取消翻转一旦开始。使用 NSOperationQueue 我可以观察 operationCount 属性以了解是否正在运行, cancelAllOperations 删除排队的块。



我浏览了并发编程指南和GCD文档,虽然有一种方法来暂停队列,没有办法阻止它们,并删除所有已排队和未运行的对象。



所以: -



<
  • 如何取消尚未运行的块?

  • 如何取消已经添加到队列中的块是否仍在等待? / li>
  • 我是GCD新手,所以我可以正确吗?


  • 解决方案

    这是使用GCD编程时的一个半常见问题。



    简单的答案是GCD没有队列的取消API 。理由:


    1. 内存管理将变得非常复杂,因为给定的块可能负责释放给定的内存分配。

    2. 实际上不可能停止正在运行的块而不破坏状态。

    3. 大多数需要取消逻辑的代码已在私有数据结构中跟踪该状态。

    ,编写如下代码是非常有效和强大的:

      dispatch_async(my_obj-> queue,^ {
    bool done = false;
    // do_full_update()花费的时间太长,因此:
    while(!my_obj-> canceled&&!done){
    done = do_partial_update my_obj);
    }
    });

    哦,要知道队列是否已经完成了所有的入队块,请使用同步 API执行空白块:

      dispatch_sync(my_obj-> queue,^ { }); 

    正如注释中提到的,更好的方式知道什么时候完成你的工作是使用派遣组。将所有块分派给组,然后可以向组中添加完成处理程序。一旦工作完成,完成块将运行。

      dispatch_group_t myGroup = dispatch_group_create 
    dispatch_group_async(myGroup,my_obj-> queue,^ {
    bool done = false;
    while(!my_obj-> canceled&&!done){
    done = do_partial_update(my_obj);
    }
    });
    dispatch_group_notify(myGroup,my_obj-> queue,^ {
    NSLog(@Work is done!);
    dispatch_release(myGroup);
    }所有块完成后,组将为空并触发通知块。



    <从那里,你可以更新UI等。



    祝你好运,玩得开心!


    I'm just playing around with GCD and I've written a toy CoinFlipper app.

    Here's the method that flips the coins:

    - (void)flipCoins:(NSUInteger)nFlips{
    
        // Create the queues for work
        dispatch_queue_t mainQueue = dispatch_get_main_queue();
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL);
    
        // Split the number of flips into whole chunks of kChunkSize and the remainder.
        NSUInteger numberOfWholeChunks = nFlips / kChunkSize;
        NSUInteger numberOfRemainingFlips = nFlips - numberOfWholeChunks * kChunkSize;
    
        if (numberOfWholeChunks > 0) {
            for (NSUInteger index = 0; index < numberOfWholeChunks; index++) {
                dispatch_async(queue, ^{
                    NSUInteger h = 0;
                    NSUInteger t = 0;
                    flipTheCoins(kChunkSize, &h, &t);
                    dispatch_async(mainQueue, ^{
                        self.nHeads += h;
                        self.nTails += t;
                    });
                });
            }
        }
        if (numberOfRemainingFlips > 0) {
            dispatch_async(queue, ^{
                NSUInteger h = 0;
                NSUInteger t = 0;
                flipTheCoins(numberOfRemainingFlips, &h, &t);
                dispatch_async(mainQueue, ^{
                    self.nHeads += h;
                    self.nTails += t;
                });
            });
    
        }
    }
    

    As you can see; I'm breaking the number of flips into large chunks flipping them in the background and updating properties in the main queue. The properties are being observed by the window controller and an UI is updated with the running results.

    I've looked through the Concurrency Programming Guide and the GCD docs, and although there is a way to suspend a queue, there isn't a way to stop them, and remove all queued and not running objects.

    I'd like to be able to hook up a 'stop' button to cancel flipping once it's started. With NSOperationQueue I can observe the operationCount property to know if it's running, and cancelAllOperations to remove queued blocks.

    I've looked through the Concurrency Programming Guide and the GCD docs, and although there is a way to suspend a queue, there isn't a way to stop them, and remove all queued and not running objects.

    So :-

    1. How do I tell if blocks I've added to a queue are still waiting?
    2. How do I cancel blocks that haven't run yet?
    3. I'm new to the GCD stuff, so am I doing it right?

    解决方案

    This is a semi-common question when programming with GCD.

    The short answer is that GCD does not have a cancelation API for queues. The rationale:

    1. memory management would become vastly more complicated, because a given block might be responsible for free()ing a given allocation of memory. By always running the block, GCD ensures that memory management remains easy.
    2. It is practically impossible to halt a running block without corrupting state.
    3. Most code that needs cancellation logic is already tracking that state in private data structures.

    Given all of these cases, it is far more efficient and powerful to write code like this:

    dispatch_async(my_obj->queue, ^{
        bool done = false;
        // do_full_update() takes too long, therefore:
        while ( !my_obj->cancelled && !done ) {
            done = do_partial_update(my_obj);
        }
    });
    

    Oh, and to know if a queue has finished running all of the enqueued blocks, your code can simply execute an empty block with the synchronous API:

    dispatch_sync(my_obj->queue, ^{});
    

    As mentioned in the comments, a better way of knowing when your work is done is to use dispatch groups. Dispatch all your blocks to the group and then you can add a completion handler to the group. Once the work is complete, the completion block will run.

    dispatch_group_t myGroup = dispatch_group_create();
    dispatch_group_async(myGroup, my_obj->queue, ^{
        bool done = false;
        while ( !my_obj->cancelled && !done ) {
            done = do_partial_update(my_obj);
        }
    });
    dispatch_group_notify(myGroup, my_obj->queue, ^{
        NSLog(@"Work is done!");
        dispatch_release(myGroup);
    });
    

    Once all of your blocks have completed, the group will be empty and trigger the notification block. From there, you can update UI, etc.

    Good luck and have fun!

    这篇关于调度队列:如何判断它们是否正在运行以及如何阻止它们的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆