C++ 从不同线程执行curl\u multi\u perform导致崩溃

C++ 从不同线程执行curl\u multi\u perform导致崩溃,c++,multithreading,curl,libcurl,nghttp2,C++,Multithreading,Curl,Libcurl,Nghttp2,在我正在进行的项目中,我需要在必要时拨打GET电话和POST电话。“GET”调用用于创建从服务器到设备的下行通道,以监视云服务器中发生的任何有趣事件。“POST”调用用于将数据发送到服务器。服务器有一个限制,即只需与服务器保持一个连接。因为服务器支持HTTP2,所以我使用“CURLMOPT\u MAX\u HOST\u CONNECTIONS”,通过将其设置为1,我将CURL设置为使用1个连接,我使用CURLMOPT\u管道,通过将其设置为CURLPIPE\u MULTIPLEX,我将多路传输。

在我正在进行的项目中,我需要在必要时拨打GET电话和POST电话。“GET”调用用于创建从服务器到设备的下行通道,以监视云服务器中发生的任何有趣事件。“POST”调用用于将数据发送到服务器。服务器有一个限制,即只需与服务器保持一个连接。因为服务器支持HTTP2,所以我使用“CURLMOPT\u MAX\u HOST\u CONNECTIONS”,通过将其设置为1,我将CURL设置为使用1个连接,我使用CURLMOPT\u管道,通过将其设置为CURLPIPE\u MULTIPLEX,我将多路传输。问题是,在第二个线程上调用“curl\u multi\u perform”时,代码崩溃

PS:这是我原始代码的一部分,可能不会立即编译/运行

#include <stdio.h>
#include <string> 
#include <sstream>
#include <curl.h>
#include <pthread.h>


#define EVENTS_URL "https://avs-alexa-na.amazon.com/v20160207/events"
#define DOWNCHANNEL_URL "https://avs-alexa-na.amazon.com/v20160207/directives"

CURLM *multi_handle;
CURL *downchannel_handle;
CURL *eventHttp_handle;

size_t processDownchannelResponse(void *ptr, size_t size, size_t nmemb, void *instance)
{

  printf(" There is downchannel response.");
}

size_t eventResponse(void *ptr, size_t size, size_t nmemb, void *instance)
{
  printf("We got eventResponse");
}
/* The downchannel thread needs to be running always 
, if the transfer is done the connection is closed 
we need to open a new connection and wait for more events*/

void createDownchannel()
{
  int retryCount =0;
  std::string downchURL = DOWNCHANNEL_URL;
  long response_code;
  int runninghandles =0;

downchannel_handle = curl_easy_init();

if(downchannel_handle == NULL){
  printf("createDownchannel : Not able to create curl handle");  
  return  ; 
}



struct curl_slist *header = NULL;
header = curl_slist_append(header, "Host: avs-alexa-na.amazon.com"); 
header = curl_slist_append(header, "TOKEN GOES HERE");

curl_easy_setopt(downchannel_handle, CURLOPT_URL, downchURL.c_str()); 
curl_easy_setopt(downchannel_handle, CURLOPT_SSL_VERIFYPEER, 0L); 
curl_easy_setopt(downchannel_handle, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(downchannel_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE); 
curl_easy_setopt(downchannel_handle, CURLOPT_WRITEFUNCTION, processDownchannelResponse); 
curl_easy_setopt(downchannel_handle, CURLOPT_WRITEDATA, NULL);
curl_easy_setopt(downchannel_handle, CURLOPT_PIPEWAIT, 1L); 

if (header) 
  curl_easy_setopt(downchannel_handle, CURLOPT_HTTPHEADER, header);


if(multi_handle)
/* add the individual easy handle */
  curl_multi_add_handle(multi_handle, downchannel_handle);

mbexitdownchannelthread = 1;

do{
  CURLMcode mc;
  int numfds;
  mc = curl_multi_perform(multi_handle, &runninghandles);
  if(mc != CURLM_OK) {
    fprintf(stderr, "curl_multi failed, code %d.n", mc);
    printf(“a<---curl_multi failed, code %d.n", mc);
    break;
  }
  printf("a<--downchannel while");
// downchannel timeout can be higher  10 seconds
  mc = curl_multi_wait(multi_handle, NULL, 0, 10000, &numfds);
  if(mc != CURLM_OK) {
    fprintf(stderr, "curl_multi failed, code %d.n", mc);
    printf("a<---curl_multi failed, code %d.n", mc);
    break;
  }

}while(!mbexitdownchannelthread);


curl_multi_remove_handle(multi_handle, downchannel_handle);

curl_easy_cleanup(downchannel_handle);

if (header)
  curl_slist_free_all(header);


}

bool getTransferStatus(CURLM *multiHandleInstance,CURL *currentHandle,std::string& contentType,int* http_status_code)
{
//check the status of transfer    CURLcode return_code=0;
  int msgs_left=0;
  CURLMsg *msg=NULL;
  CURL *eh=NULL;
  CURLcode return_code; 

  bool msgTrasferDone = false; 

  while ((msg = curl_multi_info_read(multiHandleInstance, &msgs_left))) 
  {  
    if (msg->msg == CURLMSG_DONE) {
      eh = msg->easy_handle;
      if(currentHandle == eh)
      {
        msgTrasferDone = true;
        return_code = msg->data.result;
        if(return_code!=CURLE_OK) 
        {
//fprintf(stderr, "CURL error code: %d\n", msg->data.result);
          printf("a<--return_code!=CURLE_OK CURL error code: %d\n", msg->data.result);
          continue;
        }  
// Get HTTP status code
        *http_status_code=0;
        char* ch= NULL;
        curl_easy_getinfo(eh, CURLINFO_RESPONSE_CODE, http_status_code);
        printf("a<--CURLINFO_RESPONSE_CODE=%d",*http_status_code);
        curl_easy_getinfo(eh, CURLINFO_CONTENT_TYPE, &ch);
        contentType.clear();
        if(ch!=NULL)
          contentType.append(ch);
      }
    }
  }
  return msgTrasferDone;
}

int eventThread()
{ 
  int still_running = 0;

  std::string contentType;
  int responseCode = 0;
  int numfds = 0; 
  std::string postUrl;
  postUrl.assign(EVENTS_URL);

// init the curl session 
  CURL *eventHttp_handle;
  CURLcode res;
  eventHttp_handle = curl_easy_init();

//assign speech buffer pointer for read callbacks

  curl_easy_setopt(eventHttp_handle, CURLOPT_URL, postUrl.c_str()); 
  curl_easy_setopt(eventHttp_handle, CURLOPT_SSL_VERIFYPEER, 0L); 
  curl_easy_setopt(eventHttp_handle, CURLOPT_SSL_VERIFYHOST, 0L);
  curl_easy_setopt(eventHttp_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE); 

/* wait for pipe connection to confirm */ 
  curl_easy_setopt(eventHttp_handle, CURLOPT_PIPEWAIT, 1L); 

  curl_easy_setopt(eventHttp_handle, CURLOPT_WRITEFUNCTION, eventResponse); 
  curl_easy_setopt(eventHttp_handle, CURLOPT_WRITEDATA, NULL);

  struct curl_slist *header = NULL;
  header = curl_slist_append(header, "Host: avs-alexa-na.amazon.com"); 
  header = curl_slist_append(header, "TOKEN GOES HERE");

  if (header) 
    curl_easy_setopt(eventHttp_handle, CURLOPT_HTTPHEADER, header);

  if (multi_handle) 
    curl_multi_add_handle(multi_handle, eventHttp_handle);


  do 
  {     
    {
      CURLMcode mc;
      int numfds;
      mc = curl_multi_perform(multi_handle, &still_running);
      if(mc != CURLM_OK) {
        fprintf(stderr, "curl_multi failed, code %d.n", mc);
        printf("a<---curl_multi failed, code %d.n", mc);
        break;
      }
      mc = curl_multi_wait(multi_handle, NULL, 0, 1000, &numfds);
      if(mc != CURLM_OK) {
        fprintf(stderr, "curl_multi failed, code %d.n", mc);
        printf("a<---curl_multi failed, code %d.n", mc);
        break;
      }

    }

  }while(!getTransferStatus(multi_handle,eventHttp_handle,contentType,&responseCode));


  if (header)
    curl_slist_free_all(header);

  if (formpost)
  { 
    curl_formfree(formpost); 
    formpost = NULL; 
  } 

  printf("a<-- CURL  HTTP RESP CODE =%d",responseCode);

  curl_multi_remove_handle(multi_handle, eventHttp_handle); 
  curl_easy_cleanup(eventHttp_handle); 
  return 0;
}






int main ()
{
  multi_handle = curl_multi_init();
  curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
  curl_multi_setopt(multi_handle, CURLMOPT_MAX_HOST_CONNECTIONS, 1L);

// create a downchannel thread
  pthread_attr_t attr;
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  int err = pthread_create(&mPostThread, &attr, downchannelThread,NULL);
  pthread_attr_destroy(&attr);

// i am doing some work here //
  sleep(3);

// create a event thread
  pthread_attr_t attr;
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  int err = pthread_create(&mPostThread, &attr, eventThread,NULL);
  pthread_attr_destroy(&attr);
}
#包括
#包括
#包括
#包括
#包括
#定义事件\u URL“https://avs-alexa-na.amazon.com/v20160207/events"
#定义下行通道\u URL“https://avs-alexa-na.amazon.com/v20160207/directives"
CURLM*多U手柄;
卷曲*下通道_手柄;
CURL*eventHttp_句柄;
大小\u t processDownchannelResponse(void*ptr、大小\u t size、大小\u t nmemb、void*实例)
{
printf(“存在下行通道响应”);
}
大小事件响应(void*ptr、大小、大小nmemb、void*实例)
{
printf(“我们得到了eventResponse”);
}
/*下行通道线程需要始终运行
,如果传输完成,则连接关闭
我们需要打开新连接并等待更多事件*/
void createDownchannel()
{
int retryCount=0;
std::string downchURL=下行通道URL;
长响应编码;
int runninghandles=0;
下通道句柄=curl\u easy\u init();
if(下行通道_句柄==NULL){
printf(“createDownchannel:无法创建卷曲句柄”);
返回;
}
struct curl_slist*header=NULL;
header=curl\u slist\u append(header,“主机:avs-alexa na.amazon.com”);
header=curl\u slist\u append(header,“TOKEN在这里”);
curl_easy_setopt(下行通道句柄,CURLOPT_URL,downchURL.c_str());
curl\u easy\u setopt(下行通道句柄,CURLOPT\u SSL\u验证对等,0L);
curl\u easy\u setopt(下行通道句柄,CURLOPT\u SSL\u验证主机,0L);
curl\u easy\u setopt(下行通道句柄、CURLOPT\u HTTP\u版本、curl\u HTTP\u版本2\u先验知识);
curl\u easy\u setopt(下行通道句柄、CURLOPT\u WRITEFUNCTION、processDownchannelResponse);
curl_easy_setopt(下行通道句柄,CURLOPT_WRITEDATA,NULL);
卷曲轻松设置(下通道手柄,卷曲管等待,1L);
如果(标题)
curl_easy_setopt(下行通道手柄、CURLOPT_HTTPHEADER、header);
if(多线程句柄)
/*添加单独的易处理*/
卷曲多加控制柄(多控制柄、下通道控制柄);
mbexitdownchannelthread=1;
做{
卷曲码mc;
int-numfds;
mc=curl\u multi\u perform(多句柄和运行句柄);
如果(mc!=CURLM_OK){
fprintf(标准,“卷曲多个失败,代码%d.n”,mc);

printf(“a”代码崩溃)-此时您要做的第一件事是在设置调试器时检查代码。然后,在调试器中运行代码,复制崩溃并检查调用堆栈和变量,以查看您对代码执行行为的假设与实际行为的不同之处。我个人首先要验证每个调用是否返回成功的结果()。嗨,Craig,我知道代码在哪里崩溃,代码在第二个线程上调用“curl\u multi\u perform”时崩溃。听起来你好像没有遵守这一点:嗨,Daniel,很高兴再次与你互动。从你发送的链接来看,“在多个线程中,你永远不能共享同一个句柄”这是否意味着我不能在不同的线程中将句柄添加到同一个multi_句柄并调用CURLmulti_perform?@DanielStenberg你能帮忙吗,我有点被困在如何处理这个问题上。