Как я могу немедленно отменить операцию скручивания? - PullRequest
6 голосов
/ 16 декабря 2010

Я использую libcurl в C ++, и я звоню curl_easy_perform в отдельном потоке от моего пользовательского интерфейса, используя Boost.Thread .

.В основном пользовательском интерфейсе есть кнопка отмены, которую я бы хотел, чтобы она была полностью отзывчивой (т. е. когда пользователь нажимает на нее, она должна немедленно реагировать).Я прочитал, записал и обработал колбэки, настроенные для чтения атомарной переменной should_cancel (как в этом вопросе), но есть две проблемы:

  1. Часто очень малая (но заметная) задержка с момента нажатия кнопки отмены до завершения операции скручивания.

  2. Время от времени бывает очень большая (иногда бесконечная) задержка.В этом случае либо:

    a.обратные вызовы progress, read и write просто долго не вызывались, или

    b.вызывается обратный вызов прогресса , , я возвращаю ненулевое значение (что означает, что оно должно завершиться), но операция curl не завершается некоторое время дольше (фактически, функция прогресса вызывается снова в это время!)

Итак:

  1. Почему происходят длинные задержки (особенно без вызова функции прогресса)?
  2. Что мне делать вместо этогочтобы кнопка отмены реагировала должным образом?

Одна из возможностей - сообщить пользовательскому интерфейсу, что операция отмены выполнена успешно, но продолжайте запускать завиток в фоновом режиме, пока он не отменится.Проблема с этим (я думаю) заключается в том, что она заставляет переменную should_cancel быть глобальной, а не выходить в область действия диалогового окна, в котором началась операция.

Ответы [ 3 ]

10 голосов
/ 24 августа 2011

Я встретил ту же проблему с curl 7.21.6.При попытке прервать протокол SMTP.Возврат CURL_READFUNC_ABORT из обратного вызова чтения останавливает передачу, но curl_easy_perform не возвращается в течение следующих 5+ минут.Возможно, он ожидает тайм-аута tcp.

Чтобы обойти это, я храню сокет, используемый curl (замените curl_opensocket_callback), и закройте этот сокет непосредственно при необходимости.

4 голосов
/ 16 декабря 2010

Ваша основная идея верна. Вы должны отсоединить операцию curl от пользовательского интерфейса. Однако реализация должна быть немного изменена. Вы не должны использовать глобальный should_cancel. Вместо этого у вас должен быть глобальный current_request указатель на объект типа Request. Этот тип должен иметь внутренний флаг cancel и общедоступную функцию Cancel(). В ответ на кнопку отмены вы набираете Cancel на current_request и затем обнуляете ее. Отмененный запрос затем отвечает за собственную очистку позднее (в конце концов, это поток).

Вы должны быть осторожны со своими мьютексами, чтобы предотвратить появление объектов зомби. Между отменой и завершением запроса есть неотъемлемое условие гонки.

1 голос
/ 16 декабря 2010

Задержка может быть вызвана тем, что curl_easy_perform занят обратным вызовом записи или чтения, попробуйте вернуть 0 из обратного вызова записи или CURL_READFUNC_ABORT обратным вызовом чтения. Согласно документации, если значение, возвращаемое обратным вызовом записи, отличается от значения, полученного функцией, передача будет прервана, и если обратный вызов чтения вернет CURL_READFUNC_ABORT, передача также будет прервана (действует с версии 7.12.1 библиотеки).

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