1

关于如何最好地取消其他线程上的阻塞作业,这可能是一个更通用的问题,但我对 Grand Central Dispatch 上下文中的解决方案感兴趣。我需要调用一个基本上阻塞的函数,直到它从网络获取数据;它可能会被永远阻止。我现在已经设置好了,这个被阻塞的调用发生在一个私有调度队列上,当我得到数据时,我把一个块放回主队列。问题是,一旦我调度了我的私有队列块和阻塞调用,我永远无法真正取消它。想象一下,这种能力与用户设置切换相关联。如果他们关闭,我希望这个阻塞作业和执行块基本上刚刚结束。这类问题有好的解决方案吗?

谢谢

- (void)_beginListeningForNetworkJunk
{
    dispatch_async(my_private_queue, ^{
        // blocks until it gets data
        id data = [NetworkListener waitForData];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self _handleNetworkData:data];
        });
    });
}

- (void)_endListeningForNetworkJunk
{
   // How do I kill that job that is blocked on my private queue?
}
4

2 回答 2

1

你不能。问题在于NetworkListener它的阻塞和不间断接口。

通常,您会编写代码块以异步服务网络连接,并监视其他一些信号机制,例如自定义运行循环源(NSPort或管道文件描述符或......)。当网络连接有活动时,就会得到服务。当信号机制触发时,您将关闭网络连接并退出该块。

通过这种方式,可以通过其合作取消该块。

由于您的块卡在 中-waitForData,因此无法合作。没有他们的合作,没有取消区块的机制。NSOperation 和 NSThread 也是如此。原因是没有它的合作,终止另一个线程的活动基本上是不可行的。

您的网络代码需要不同的设计。

于 2012-05-28T20:06:13.073 回答
0

原则上,您不能取消在任何其他线程上运行的任何内容。您只能礼貌地要求在另一个线程上运行的任务取消。我通常创建代表任务的对象,以便可以在这些对象上调用“取消”。

在您的情况下:无法取消 waitForData(除非 NetworkListener 有一些 API 可以执行此操作;在这种情况下,waitForData 需要某种机制来区分数据到达和取消)。

在 _endListenForNetworkJunk 中,可以设置一个 BOOL 值“cancelled”来表示呼叫被取消。然后在主队列上运行的代码中,检查“取消”值是否仍然被清除。这样,如果你从主线程调用 _endListenForNetworkJunk,你肯定不会调用 _handleNetworkData。如果您从另一个线程调用 _endListenForNetworkJunk,则主线程可能刚刚开始调用 _handleNetworkData。

如果您在分派到主队列之前选中“已取消”,则该块可能已经分派但在您在主线程上调用 _endListenForNetworkJunk 之前没有执行。

于 2014-03-26T18:48:22.913 回答