Chinaunix首页 | 论坛 | 博客
  • 博客访问: 234920
  • 博文数量: 31
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 296
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-22 11:52
文章分类

全部博文(31)

文章存档

2018年(3)

2017年(11)

2016年(12)

2015年(5)

我的朋友

分类: C/C++

2017-06-30 17:30:12

  程序跑的好好的,改成多线程就各种segfault 了,看到都心累,只能gdb 慢慢调了,每次都是在ssl_connect的时候就出错,认真重新检查了一遍ssl_connect 之前的所有步骤,man 了个个函数,发现SSL_library_init() 是不可重入的,openssl的官网也有说明,1.1.0 之前的版本SSL connect是不支持并行的,要是升级openssl 库估计更大工程,原来的很多模块都是根据openssl 1.0.1 实现的,升级是不现实的,只能先修改程序,使得它在openssl1.0.1 下多线程能跑得好好的,折腾一番下来,总算改好了。总结一下,要在1.0.1的openssl库下编写多线程的代码的解决方法:

1.确认openssl 库编译的时候打开了支持多线程的开关,在openssl库的源码目录下面的install 文件有说明,默认是用threads 参数的,  就是支持多线程的,有些系统还需要-D_REENTRANT 参数,./configure 的时候记得带上这些参数;
2.用到SSL_library_init 等不可重入的函数的时候,要加锁;
3.在crypto 库里面还有设置两个回调函数,使用例子可参考openssl源码目录下面的crypto/threads/mttest.c,主要就是在线程开始之
 前设置两个回调函数,这两个回调函数分别是获取线程id和加锁的函数,贴一下关键代码,如下:

点击(此处)折叠或打开

  1. static pthread_mutex_t *lock_cs;
  2. static long *lock_count;

  3. 线程开始之前先注册回调函数,就是为每一个线程注册一个lock,当调用crypto库里面的函数的时候,可通过
  4. 回调函数加锁

  5. void thread_setup(void)
  6. {
  7.         int i;

  8.         lock_cs=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
  9.         lock_count=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
  10.         for (i=0; i<CRYPTO_num_locks(); i++)
  11.                 {
  12.                 lock_count[i]=0;
  13.                 pthread_mutex_init(&(lock_cs[i]),NULL);
  14.                 }

  15.         CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);
  16.         CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);
  17. }

  18. 线程结束之后,释放空间
  19. void thread_cleanup(void)
  20. {
  21.         int i;

  22.         CRYPTO_set_locking_callback(NULL);
  23.         fprintf(stderr,"cleanup\n");
  24.         for (i=0; i<CRYPTO_num_locks(); i++)
  25.                 {
  26.                 pthread_mutex_destroy(&(lock_cs[i]));
  27.                 fprintf(stderr,"%8ld:%s\n",lock_count[i],
  28.                         CRYPTO_get_lock_name(i));
  29.                 }
  30.         OPENSSL_free(lock_cs);
  31.         OPENSSL_free(lock_count);

  32.         fprintf(stderr,"done cleanup\n");
  33. }

  34. 回调函数一,加锁用的函数
  35. void pthreads_locking_callback(int mode, int type, char *file,
  36.              int line)
  37. {

  38.         if (mode & CRYPTO_LOCK)
  39.                 {
  40.                 pthread_mutex_lock(&(lock_cs[type]));
  41.                 lock_count[type]++;
  42.                 }
  43.         else
  44.                 {
  45.                 pthread_mutex_unlock(&(lock_cs[type]));
  46.                 }
  47. }

  48. 回调函数二,返回线程id ,用来取得对应的锁
  49. unsigned long pthreads_thread_id(void)
  50. {
  51.         unsigned long ret;

  52.         ret=(unsigned long)pthread_self();
  53.         return(ret);
  54. }

总结一下,发现man 和官网绝对是个好东西,没事可以多读读man 手册,尤其各个API 的用法,存在的缺陷都会有说明。





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