我有一个庞大的代码(我的学校项目),我使用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
的线程调用为每个线程创建自己的私有变量,应该没有问题...请帮助:)
答案 0 :(得分:4)
查看OpenSSL源代码树中的示例openssl/crypto/threads/mttest.c
。基本上,您必须提供两个回调函数:
使用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