Swift 取消 DispatchQueue 进程

Swift Cancel DispatchQueue Process

我有一个 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 {
       ...
    }
}

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

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

为超时间隔声明一个常量,为定时器声明一个属性

private let timeoutSeconds = 30
private var timer : DispatchSourceTimer?

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

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
}

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

没有办法从外面停止或"kill"一个DispatchWorkItemNSOperation。有一个 cancel() 方法,但它只是将项目或操作的 isCancelled 属性 设置为 true。这 不会 停止项目本身的执行。 Ans 由于 recv 正在阻塞,因此无法在执行期间检查 isCancelled 标志。这意味着 Vadian 发布的答案很遗憾不会做任何事情。

根据 NSOperation.cancel 上的 Apple docs

This method does not force your operation code to stop.

The same 对应 NSOperationQueue.cancelAllOperations:

Canceling the operations does not automatically remove them from the queue or stop those that are currently executing.

您可能认为可以使用原始 NSThread。然而,同样的原则适用于他。您不能确定性地从外部杀死线程。

可能的解决方案:超时

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

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

您可以尝试的另一种选择是在经过一定时间后向您自己发送一些 UDP 数据包。这样,recv 会收到一些数据,然后继续执行。这可能用作 "poor man's timeout".

不应该是 UDPServer 不会 return 的任何情况。 UDPServer 应该等待多长时间应该有超时限制。例如考虑以下情况:

 DispatchQueue.global(qos: .background).async {
 let server = UDPServer(address:"0.0.0.0", port:5005)
    switch server.recv(1024) {
        case .success:
            print("Server received message from client.")
        case .failure(let error):
            print("Server failed to received message from client: \(error)")
        }

        server.close()
        DispatchQueue.main.async {
            ...
        }
    }