Быстрая отмена процесса отправкиQueue - PullRequest
0 голосов
/ 17 января 2019

У меня есть метод 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 никогда не возвращается, поэтому я не вижу, как этот процесс закончится? Есть ли способ дать ему заранее определенное количество времени для бега?

Ответы [ 3 ]

0 голосов
/ 26 января 2019

Нет способа остановить или «убить» DispatchWorkItem или NSOperation извне. Существует метод cancel(), но он просто устанавливает для свойства isCancelled элемента или операции значение true. Это не останавливает выполнение самого элемента. Так как recv блокирует, нет возможности проверить флаг isCancelled во время выполнения. Это означает, что ответ, опубликованный Vadian, к сожалению, ничего не сделает.

Согласно Apple Docs на NSOperation.cancel:

Этот метод не заставляет ваш код операции останавливаться.

То же самое относится к NSOperationQueue.cancelAllOperations:

Отмена операций не приводит к автоматическому удалению их из очереди или остановке тех, которые выполняются в данный момент.

Вы можете подумать, что можно использовать необработанный NSThread. Однако тот же принцип применяется и здесь. Вы не можете детерминистически уничтожить поток извне.

Возможное решение: время ожидания

Лучшее решение, которое я могу придумать, это использовать функцию тайм-аута сокета. Я не знаю, откуда берется UDPServer, но, возможно, у него есть встроенное время ожидания.

Возможное решение: Тайм-аут плохого человека (отправка пакета на локальный хост)

Другой вариант, который вы можете попробовать, это отправить себе UDP-пакеты по истечении определенного времени. Таким образом, recv получит некоторые данные, и выполнение будет продолжено. Это может быть использовано как «тайм-аут бедняка».

0 голосов
/ 27 января 2019

Где не должно быть ни одного случая, когда UDPServer не вернется.Должен быть предел времени ожидания для того, как долго 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 {
            ...
        }
    }
0 голосов
/ 22 января 2019

Добавить таймер, который срабатывает после определенного интервала времени ожидания

Объявить константу для интервала времени ожидания и свойство для таймера

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 для обработки тайм-аута, например, для освобождения экземпляра сервера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...