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

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

问题描述

我只是在玩 GCD,我已经编写了一个玩具 CoinFlipper 应用程序.

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

这是抛硬币的方法:

- (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;
            });
        });

    }
}

如你所见;我将翻转次数分成大块,在后台翻转它们并更新主队列中的属性.窗口控制器正在观察这些属性,并使用运行结果更新 UI.

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.

我浏览了并发编程指南和 GCD 文档,虽然有一种方法可以挂起队列,但没有一种方法可以停止它们,并删除所有已排队但未运行的对象.

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.

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

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.

我浏览了并发编程指南和 GCD 文档,虽然有一种方法可以挂起队列,但没有一种方法可以停止它们,并删除所有已排队但未运行的对象.

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.

所以:-

  1. 如何判断已添加到队列中的块是否仍在等待?
  2. 如何取消尚未运行的块?
  3. 我是 GCD 的新手,所以我做得对吗?

推荐答案

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

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

简短的回答是 GCD 没有用于队列的取消 API.理由:

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

  1. 内存管理将变得更加复杂,因为给定的块可能负责释放()给定的内存分配.通过始终运行该块,GCD 确保内存管理仍然容易.
  2. 几乎不可能在不破坏状态的情况下停止正在运行的块.
  3. 大多数需要取消逻辑的代码已经在私有数据结构中跟踪该状态.

考虑到所有这些情况,编写这样的代码会更加高效和强大:

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);
    }
});

哦,要知道队列是否已完成所有入队块的运行,您的代码可以简单地使用同步 API 执行一个空块:

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);
});

一旦您的所有块都完成,该组将为空并触发通知块.从那里,您可以更新 UI 等.

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

祝你好运,玩得开心!

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

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