• 多线程的libcurl的使用


    摘要:libcurl在多线程中,采用https访问,经常运行一段时间,会出现crash。

    libcurl的在多线程中的使用特别注意的有两点:

    1. curl的句柄不能多线程共享。

    2. ssl访问时, openssl是线程不安全的。

    知道了这两点,就能解决libcurl无故crash的问题了。

    第一点:每个线程初始化一个句柄,供这个线程使用。

    第二点:需要添加回调函数,进行线程锁。

    参考代码如下:

    #include <stdio.h>
    #include <pthread.h>
    #include <curl/curl.h>
    
    #define NUMT 4
    
    /* we have this global to let the callback get easy access to it */
    static pthread_mutex_t *lockarray;
    
    #ifdef USE_OPENSSL
    #include <openssl/crypto.h>
    static void lock_callback(int mode, int type, char *file, int line)
    {
    (void)file;
    (void)line;
    if(mode & CRYPTO_LOCK) {
    pthread_mutex_lock(&(lockarray[type]));
    }
    else {
    pthread_mutex_unlock(&(lockarray[type]));
    }
    }
    
    static unsigned long thread_id(void)
    {
    unsigned long ret;
    
    ret = (unsigned long)pthread_self();
    return ret;
    }
    
    static void init_locks(void)
    {
      int i;
      printf("crypto num is %d\r\n", CRYPTO_num_locks());
      lockarray = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() *
      sizeof(pthread_mutex_t));
      for(i = 0; i<CRYPTO_num_locks(); i++) {
      pthread_mutex_init(&(lockarray[i]), NULL);
    }
    
    CRYPTO_set_id_callback((unsigned long (*)())thread_id);
    CRYPTO_set_locking_callback((void (*)())lock_callback);
    }
    
    static void kill_locks(void)
    {
      int i;
    
      CRYPTO_set_locking_callback(NULL);
      for(i = 0; i<CRYPTO_num_locks(); i++)
        pthread_mutex_destroy(&(lockarray[i]));
    
      OPENSSL_free(lockarray);
    }
    
    
    /* List of URLs to fetch.*/
    const char * const urls[]= {
      "https://www.example.com/",
      "https://www2.example.com/",
      "https://www3.example.com/",
      "https://www4.example.com/",
    };
    
    static void *pull_one_url(void *url)
    {
      CURL *curl;
    
      curl = curl_easy_init();//每个线程初始化一个句柄,绝对不能混用。
      curl_easy_setopt(curl, CURLOPT_URL, url);
      /* this example doesn't verify the server's certificate, which means we
         might be downloading stuff from an impostor */
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
      curl_easy_perform(curl); /* ignores error */
      curl_easy_cleanup(curl);
    
      return NULL;
    }
    
    int main(int argc, char **argv)
    {
      pthread_t tid[NUMT];
      int i;
      (void)argc; /* we don't use any arguments in this example */
      (void)argv;
    
      /* Must initialize libcurl before any threads are started */
      curl_global_init(CURL_GLOBAL_ALL);
    
      init_locks();//初始化openssl的回调函数,加载线程锁
    
      for(i = 0; i< NUMT; i++) {
        int error = pthread_create(&tid[i],
                                   NULL, /* default attributes please */
                                   pull_one_url,
                                   (void *)urls[i]);
        if(0 != error)
          fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error);
        else
          fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]);
      }
    
    
      /* now wait for all threads to terminate */
    
      for(i = 0; i< NUMT; i++) {
        pthread_join(tid[i], NULL);
        fprintf(stderr, "Thread %d terminated\n", i);
      }
    
      kill_locks();//销毁openssl线程锁
    
      return 0;
    }
                       
  • 相关阅读:
    应用JConsole学习Java GC
    删除MySQL重复数据
    Linux后台运行程序
    Jvm基础(2)-Java内存模型
    一个word合并项目的分布式架构设计
    Jvm基础(1)-Java运行时数据区
    【JPA】01 快速上手
    【Ubuntu】下载安装 20.04.版本 桌面端
    【Ubuntu】下载安装 12.04.5版本 桌面端
    【CentOS】tar包安装Tomcat
  • 原文地址:https://www.cnblogs.com/damizhou/p/15815361.html
Copyright © 2020-2023  润新知