Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1003441
  • 博文数量: 96
  • 博客积分: 1553
  • 博客等级: 上尉
  • 技术积分: 1871
  • 用 户 组: 普通用户
  • 注册时间: 2011-12-25 14:50
个人简介

专注点,细心点,耐心点 知行合一

文章分类

全部博文(96)

文章存档

2018年(1)

2014年(4)

2013年(31)

2012年(56)

2011年(4)

分类: C/C++

2013-04-09 15:35:52

问题

多线程libcurl运行一段时间后出现崩掉,没有确定的点,没有确定的URL。一直查看源代码没有问题,最后通过debug跟踪发现是在访问SSL的时候出现的crash。

才想起来openssl是不支持多线程的,要自己做加锁处理。而且libcurl中并没有支持相关的加锁操作。


解决办法:

在初始化libcurl的时候为openssl创建一个互斥锁函数,一个回调函数传给openss

openssl锁l函数原形 :void (* func )(int ,int , const char * ,int)

设置方式:CRYPTO_set_locking_callback(void (* func )(int ,int , const char * ,int));

设置这样一个函数还不够,另外还要配置一个锁id回调函数,这个可以参考openssl多线程下的使用相关。

id函数原形:unsigned int (*func)(void)

设置方式:CRYPTO_set_id_callback(unsigned int (*func)(void));

通过这两个设置就可以解决HTTPS多线程请求出现crash的问题。


代码示例:

下面是引用了libcurl示例的一个代码

最关键就是,两个callback的实现,还有初始化锁(init_locks)和释放锁(kill_locks)的位置


点击(此处)折叠或打开

  1. #define USE_OPENSSL
  2.        
  3.     #include <stdio.h>
  4.     #include <pthread.h>
  5.     #include <curl/curl.h>
  6.        
  7.     #define NUMT 4
  8.        
  9.     /* we have this global to let the callback get easy access to it */
  10.     static pthread_mutex_t *lockarray;
  11.        
  12.     #ifdef USE_OPENSSL
  13.     #include <openssl/crypto.h>
  14.     static void lock_callback(int mode, int type, char *file, int line)
  15.     {
  16.       (void)file;
  17.       (void)line;
  18.       if (mode & CRYPTO_LOCK) {
  19.         pthread_mutex_lock(&(lockarray[type]));
  20.       }
  21.       else {
  22.         pthread_mutex_unlock(&(lockarray[type]));
  23.       }
  24.     }
  25.        
  26.     static unsigned long thread_id(void)
  27.     {
  28.       unsigned long ret;
  29.        
  30.       ret=(unsigned long)pthread_self();
  31.       return(ret);
  32.     }
  33.        
  34.     static void init_locks(void)
  35.     {
  36.       int i;
  37.        
  38.       lockarray=(pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() *
  39.                                                 sizeof(pthread_mutex_t));
  40.       for (i=0; i<CRYPTO_num_locks(); i++) {
  41.         pthread_mutex_init(&(lockarray[i]),NULL);
  42.       }
  43.        
  44.       CRYPTO_set_id_callback((unsigned long (*)())thread_id);
  45.       CRYPTO_set_locking_callback((void (*)())lock_callback);
  46.     }
  47.        
  48.     static void kill_locks(void)
  49.     {
  50.       int i;
  51.        
  52.       CRYPTO_set_locking_callback(NULL);
  53.       for (i=0; i<CRYPTO_num_locks(); i++)
  54.         pthread_mutex_destroy(&(lockarray[i]));
  55.        
  56.       OPENSSL_free(lockarray);
  57.     }
  58.     #endif
  59.        
  60.     #ifdef USE_GNUTLS
  61.     #include <gcrypt.h>
  62.     #include <errno.h>
  63.        
  64.     GCRY_THREAD_OPTION_PTHREAD_IMPL;
  65.        
  66.     void init_locks(void)
  67.     {
  68.       gcry_control(GCRYCTL_SET_THREAD_CBS);
  69.     }
  70.        
  71.     #define kill_locks()
  72.     #endif
  73.        
  74.     /* List of URLs to fetch.*/
  75.     const char * const urls[]= {
  76.       "",
  77.       "",
  78.       "",
  79.       "",
  80.     };
  81.        
  82.     static void *pull_one_url(void *url)
  83.     {
  84.       CURL *curl;
  85.        
  86.       curl = curl_easy_init();
  87.       curl_easy_setopt(curl, CURLOPT_URL, url);
  88.       /* this example doesn't verify the server's certificate, which means we
  89.          might be downloading stuff from an impostor */
  90.       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
  91.       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
  92.       curl_easy_perform(curl); /* ignores error */
  93.       curl_easy_cleanup(curl);
  94.        
  95.       return NULL;
  96.     }
  97.        
  98.     int main(int argc, char **argv)
  99.     {
  100.       pthread_t tid[NUMT];
  101.       int i;
  102.       int error;
  103.       (void)argc; /* we don't use any arguments in this example */
  104.       (void)argv;
  105.        
  106.       /* Must initialize libcurl before any threads are started */
  107.       curl_global_init(CURL_GLOBAL_ALL);
  108.        
  109.       init_locks();
  110.        
  111.       for(i=0; i< NUMT; i++) {
  112.         error = pthread_create(&tid[i],
  113.                                NULL, /* default attributes please */
  114.                                pull_one_url,
  115.                                (void *)urls[i]);
  116.         if(0 != error)
  117.           fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error);
  118.         else
  119.           fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]);
  120.       }
  121.        
  122.       /* now wait for all threads to terminate */
  123.       for(i=0; i< NUMT; i++) {
  124.         error = pthread_join(tid[i], NULL);
  125.         fprintf(stderr, "Thread %d terminated\n", i);
  126.       }
  127.        
  128.       kill_locks();
  129.        
  130.       return 0;
  131.     }


点击(此处)折叠或打开

  1. #define USE_OPENSSL
  2.        
  3.     #include <stdio.h>
  4.     #include <pthread.h>
  5.     #include <curl/curl.h>
  6.        
  7.     #define NUMT 4
  8.        
  9.     /* we have this global to let the callback get easy access to it */
  10.     static pthread_mutex_t *lockarray;
  11.        
  12.     #ifdef USE_OPENSSL
  13.     #include <openssl/crypto.h>
  14.     static void lock_callback(int mode, int type, char *file, int line)
  15.     {
  16.       (void)file;
  17.       (void)line;
  18.       if (mode & CRYPTO_LOCK) {
  19.         pthread_mutex_lock(&(lockarray[type]));
  20.       }
  21.       else {
  22.         pthread_mutex_unlock(&(lockarray[type]));
  23.       }
  24.     }
  25.        
  26.     static unsigned long thread_id(void)
  27.     {
  28.       unsigned long ret;
  29.        
  30.       ret=(unsigned long)pthread_self();
  31.       return(ret);
  32.     }
  33.        
  34.     static void init_locks(void)
  35.     {
  36.       int i;
  37.        
  38.       lockarray=(pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() *
  39.                                                 sizeof(pthread_mutex_t));
  40.       for (i=0; i<CRYPTO_num_locks(); i++) {
  41.         pthread_mutex_init(&(lockarray[i]),NULL);
  42.       }
  43.        
  44.       CRYPTO_set_id_callback((unsigned long (*)())thread_id);
  45.       CRYPTO_set_locking_callback((void (*)())lock_callback);
  46.     }
  47.        
  48.     static void kill_locks(void)
  49.     {
  50.       int i;
  51.        
  52.       CRYPTO_set_locking_callback(NULL);
  53.       for (i=0; i<CRYPTO_num_locks(); i++)
  54.         pthread_mutex_destroy(&(lockarray[i]));
  55.        
  56.       OPENSSL_free(lockarray);
  57.     }
  58.     #endif
  59.        
  60.     #ifdef USE_GNUTLS
  61.     #include <gcrypt.h>
  62.     #include <errno.h>
  63.        
  64.     GCRY_THREAD_OPTION_PTHREAD_IMPL;
  65.        
  66.     void init_locks(void)
  67.     {
  68.       gcry_control(GCRYCTL_SET_THREAD_CBS);
  69.     }
  70.        
  71.     #define kill_locks()
  72.     #endif
  73.        
  74.     /* List of URLs to fetch.*/
  75.     const char * const urls[]= {
  76.       "",
  77.       "",
  78.       "",
  79.       "",
  80.     };
  81.        
  82.     static void *pull_one_url(void *url)
  83.     {
  84.       CURL *curl;
  85.        
  86.       curl = curl_easy_init();
  87.       curl_easy_setopt(curl, CURLOPT_URL, url);
  88.       /* this example doesn't verify the server's certificate, which means we
  89.          might be downloading stuff from an impostor */
  90.       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
  91.       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
  92.       curl_easy_perform(curl); /* ignores error */
  93.       curl_easy_cleanup(curl);
  94.        
  95.       return NULL;
  96.     }
  97.        
  98.     int main(int argc, char **argv)
  99.     {
  100.       pthread_t tid[NUMT];
  101.       int i;
  102.       int error;
  103.       (void)argc; /* we don't use any arguments in this example */
  104.       (void)argv;
  105.        
  106.       /* Must initialize libcurl before any threads are started */
  107.       curl_global_init(CURL_GLOBAL_ALL);
  108.        
  109.       init_locks();
  110.        
  111.       for(i=0; i< NUMT; i++) {
  112.         error = pthread_create(&tid[i],
  113.                                NULL, /* default attributes please */
  114.                                pull_one_url,
  115.                                (void *)urls[i]);
  116.         if(0 != error)
  117.           fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error);
  118.         else
  119.           fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]);
  120.       }
  121.        
  122.       /* now wait for all threads to terminate */
  123.       for(i=0; i< NUMT; i++) {
  124.         error = pthread_join(tid[i], NULL);
  125.         fprintf(stderr, "Thread %d terminated\n", i);
  126.       }
  127.        
  128.       kill_locks();
  129.        
  130.       return 0;
  131.     }

阅读(8784) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~