Swift 取消 DispatchQueue 过程

iph*_*aaw 6 swift dispatch-queue

我有一个 UDP 方法,它使用以下代码使用 DispatchQueue 等待回复:

DispatchQueue.global(qos: .userInitiated).async {
    let server:UDPServer=UDPServer(address:"0.0.0.0", port:5005)
    let (data,_,_) = server.recv(1024)
    DispatchQueue.main.async {
       ...
    }
}
Run Code Online (Sandbox Code Playgroud)

这非常有效,并启动了一个等待我的数据进来的过程。如果我们从未收到回复,让我夜不能寐的是会发生什么?server.recv 永远不会返回,所以我看不到这个过程将如何结束?有没有办法给它预定的运行时间?

Ren*_*ers 6

没有办法阻止或“杀死”aDispatchWorkItemNSOperation从外部。有一种cancel()方法,但它只是将isCancelled项目或操作的属性设置为 true。这并没有阻止该项目本身的执行。Ans 由于recv正在阻塞,因此无法isCancelled在执行期间检查标志。这意味着不幸的是 Vadian 发布的答案不会做任何事情。

按照苹果的文档NSOperation.cancel

此方法不会强制您的操作代码停止。

这同样适用于NSOperationQueue.cancelAllOperations

取消操作不会自动将它们从队列中删除或停止当前正在执行的操作。

您可能认为可以下降到使用原始NSThread. 但是,同样的原则也适用。您无法从外部确定性地杀死线程。

可能的解决方案:超时

我能想到的最佳解决方案是使用套接字的超时功能。我不知道UDPServer从哪里来,但也许它有一个内置的超时。

可能的解决方案:穷人的超时(发送数据包到本地主机)

您可以尝试的另一种选择是在经过一段时间后向自己发送一些 UDP 数据包。这样,recv会收到一些数据,然后继续执行。这可能被用作“穷人的超时”。


vad*_*ian 5

添加一个在特定超时间隔后触发的计时器

声明超时间隔常量和计时器属性

private let timeoutSeconds = 30
private var timer : DispatchSourceTimer?
Run Code Online (Sandbox Code Playgroud)

并编写两个函数来启动和停止计时器。

fileprivate func startDispatchTimer()
{
    let interval : DispatchTime = .now() + .seconds(timeoutSeconds)
    if timer == nil {
        timer = DispatchSource.makeTimerSource(queue: DispatchQueue.global())
        timer!.schedule(deadline:interval)
        timer!.setEventHandler {
            // do something when the timer fires
            self.timer = nil
        }
        timer!.resume()
    }
}

fileprivate func stopDispatchTimer()
{
    timer?.cancel()
    timer = nil
}
Run Code Online (Sandbox Code Playgroud)

初始化服务器实例后启动计时器并在成功时停止。失败时在setEventHandler闭包中添加代码来处理超时,例如取消分配服务器实例。