使用OpenMP和OpenSSL时内存泄漏和seg故障

时间:2014-04-07 07:35:24

标签: c multithreading openssl openmp

我有一个庞大的代码(我的学校项目),我使用Openssl。一切都工作完全,工具我决定我会多线程。我选择openmp作为我的线程环境,因为它非常简单易学(至少我需要的基础很简单)。

我的整个代码如下:

struct mystr[10];
omp_set_num_threads(10);
#pragma omp parallel 
{
    mystr[omp_get_thread_num()] = call_fun_which_uses_openssl();
}
CRYPTO_cleanup_all_ex_data();

我的call_fun_which_uses_openssl函数使用低级openssls api函数(MD4((unsigned char*)&string, strlen(string), (unsigned char*)&digest);而不是MD4_CTX ctx等)。我的函数使用RSA,DSA,...并且无法访问任何全局变量,它使用的每个变量都在call_fun_which_uses_openssl内声明,所以像我这样做多线程应该保证这些变量保持私有。虽然,我有时会使用此代码出现seg错误。我读到CRYPTO_cleanup_all_ex_data不是线程安全的(但由于内存泄漏我需要它)但是我在并行区域之外使用它,对吧?当我删除openmp次调用时,每次都有效,因此多线程和openssl一定存在问题。任何想法如何解决?

在我看来它应该工作,因为call_fun_which_uses_openssl的线程调用为每个线程创建自己的私有变量,应该没有问题...请帮助:)

1 个答案:

答案 0 :(得分:4)

查看OpenSSL源代码树中的示例openssl/crypto/threads/mttest.c。基本上,您必须提供两个回调函数:

  • 实现锁定和解锁的一个
  • 返回唯一线程ID的那个。

使用OpenMP很容易实现两者:

omp_lock_t *locks;

// Locking callback
void openmp_locking_callback(int mode, int type, char *file, int line)
{
  if (mode & CRYPTO_LOCK)
  {
    omp_set_lock(&locks[type]);
  }
  else
  {
    omp_unset_lock(&locks[type]);
  }
}

// Thread ID callback
unsigned long openmp_thread_id(void)
{
  return (unsigned long)omp_get_thread_num();
}

在开始之前,必须初始化锁定并设置回调:

void openmp_thread_setup(void)
{
  int i;

  locks = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(omp_lock_t));
  for (i=0; i<CRYPTO_num_locks(); i++)
  {
    omp_init_lock(&locks[i]);
  }

  CRYPTO_set_id_callback((unsigned long (*)())openmp_thread_id);
  CRYPTO_set_locking_callback((void (*)())openmp_locking_callback);
}

void openmp_thread_cleanup(void)
{
  int i;

  CRYPTO_set_id_callback(NULL);
  CRYPTO_set_locking_callback(NULL);
  for (i=0; i<CRYPTO_num_locks(); i++)
    omp_destroy_lock(&locks[i]);
  OPENSSL_free(locks);
}

您应该在第一个并行区域之前的某个地方调用openmp_thread_setup()一次,并且应该在最后一个并行区域之后调用openmp_thread_cleanup()一次:

// Program start

openmp_thread_setup();

#pragma omp parallel
{
   // Parallel OpenSSL calls are now data race free
}

#pragma omp parallel
{
   // Parallel OpenSSL calls are now data race free
}

#pragma omp parallel
{
   // Parallel OpenSSL calls are now data race free
}

openmp_thread_cleanup();

// Program should end now