How can I cancel a curling operation immediately?

I use libcurl in C ++ and I call curl_easy_perform in a separate thread from my user interface using Boost.Thread .

There is a cancel button in the main user interface that I would like to be very responsive (i.e. when a user clicks on it, it should respond immediately). I have read, written, and executed callbacks configured to read the should_cancel atomic variable (as in this question), but there are two problems:

  • Often there is a very small (but noticeable) delay from the moment you press cancel, when the curling operation is completed.

  • Sometimes there is a very long (sometimes endless) delay. In this case, either:

    but. messages about progress, reading and writing simply do not cause for a long time or

    b. the progress callback is called, I return a non-zero value (which means that it should end), but the curling operation does not finish for some time (in fact, the progress function is called again during this time!)

So:

  • Why are there long delays (especially without calling the progress function)?
  • What should I do to allow the cancel button to respond normally?

One possibility is to tell the user interface that the undo operation was successful, but continue to run the curly thread in the background until it is undone. The problem with this (I think) is that it causes the should_cancel variable should_cancel be global, and not tied to the dialog box where the operation started.

+6
c ++ multithreading curl boost-thread
source share
3 answers

Your basic idea is correct. You must disable the curling operation from the user interface. However, the implementation should be slightly modified. You should not use global should_cancel . Instead, you should have a current_request global pointer to an object of type Request . This type must have an internal cancel flag and a public Cancel() function. In response to the cancel button, you call cancel on current_request and then null. A canceled request is then responsible for its own cleanup later (this is the thread, after all).

You need to be careful with your mutexes to prevent zombie objects. There is an integral condition for the race between cancellation and completion of the request.

+3
source share

I met the same problem with curl 7.21.6. When tring cancels the smtp protocol. Returning CURL_READFUNC_ABORT from the read callback stops the transfer, but curl_easy_perform does not return for the next 5+ minutes. He is probably waiting for tcp timeout.

To get around this, I store the socket used by curl (replace curl_opensocket_callback), and close this socket directly when necessary.

 curl_socket_t storeCurlSocket(SOCKET *data, curlsocktype purpose, struct curl_sockaddr *addr) { SOCKET sock = socket(addr->family, addr->socktype, addr->protocol); *data = sock; return sock; } size_t abort_payload(void *ptr, size_t size, size_t nmemb, SOCKET *curl_socket) { SOCKET l_socket = INVALID_SOCKET; swap(l_socket, *curl_socket); if (l_socket != INVALID_SOCKET) { shutdown(l_socket, SD_BOTH); closesocket(l_socket); } return CURL_READFUNC_ABORT; } ...calling perform... SOCKET curlSocket; curet = curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, storeCurlSocket); curet = curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, &curlSocket); curet = curl_easy_setopt(curl, CURLOPT_READFUNCTION, abort_payload); curet = curl_easy_setopt(curl, CURLOPT_READDATA, &curlSocket); curet = curl_easy_perform(curl); if (curet == CURLE_ABORTED_BY_CALLBACK) { //expected abort } ... 
+9
source share

A delay may occur because curl_easy_perform busy with a write or read callback, try returning 0 from the write callback or CURL_READFUNC_ABORT from the read callback. According to the documentation, if the value returned by the record callback is different from the value received by the function, the transfer will be aborted, and if the return callback of the return is CURL_READFUNC_ABORT , the transfer will also be interrupted (valid from version 7.12.1 of the library).

+1
source share

All Articles