我一直在阅读有关如果在multithreading应用程序中使用OpenSSL的要求,您必须使用OpenSSL注册一个线程标识函数(以及一个互斥体创build函数)。
在Linux上,根据OpenSSL提供的例子,一个线程通常是通过注册一个这样的函数来标识的:
static unsigned long id_function(void){ return (unsigned long)pthread_self(); }
pthread_self()返回一个pthread_t,这在Linux上可行,因为pthread_t只是一个unsigned long的typedef。
在Windows pthreads,FreeBSD和其他操作系统上,pthread_t是一个结构体,结构如下:
struct { void * p; /* Pointer to actual object */ unsigned int x; /* Extra information - reuse count etc */ }
这不能简单地转换为无符号长整型,当我尝试这样做时,会抛出一个编译错误。 我尝试了void * p并将其转换为无符号长整型,理论上内存指针应该在线程间是一致且唯一的,但是这只会导致我的程序崩溃。
当使用Windows pthreads或FreeBSD或任何其他类似的操作系统时,我可以使用OpenSSL注册哪些线程识别function?
另外,还有一个问题:
有谁知道这是否也需要完成,如果OpenSSL编译进去,并与QT一起使用,如果是的话如何注册与OpenSSL的QThreads? 令人惊讶的是,我似乎无法在QT的文档中find答案。
我只是把这个代码放在这里。 这不是万能的,因为它不涉及FreeBSD,但在大多数情况下,当你需要支持Windows并且说Debian的时候,它是有用的。 当然,干净的解决方案假定使用最近推出的CRYPTO_THREADID_*
系列。 (给出一个想法,它有一个CRYPTO_THREADID_cmp
回调,它可以映射到pthread_equal
)
#include <pthread.h> #include <openssl/err.h> #if defined(WIN32) #define MUTEX_TYPE HANDLE #define MUTEX_SETUP(x) (x) = CreateMutex(NULL, FALSE, NULL) #define MUTEX_CLEANUP(x) CloseHandle(x) #define MUTEX_LOCK(x) WaitForSingleObject((x), INFINITE) #define MUTEX_UNLOCK(x) ReleaseMutex(x) #define THREAD_ID GetCurrentThreadId() #else #define MUTEX_TYPE pthread_mutex_t #define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL) #define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x)) #define MUTEX_LOCK(x) pthread_mutex_lock(&(x)) #define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x)) #define THREAD_ID pthread_self() #endif /* This array will store all of the mutexes available to OpenSSL. */ static MUTEX_TYPE *mutex_buf=NULL; static void locking_function(int mode, int n, const char * file, int line) { if (mode & CRYPTO_LOCK) MUTEX_LOCK(mutex_buf[n]); else MUTEX_UNLOCK(mutex_buf[n]); } static unsigned long id_function(void) { return ((unsigned long)THREAD_ID); } int thread_setup(void) { int i; mutex_buf = malloc(CRYPTO_num_locks() * sizeof(MUTEX_TYPE)); if (!mutex_buf) return 0; for (i = 0; i < CRYPTO_num_locks( ); i++) MUTEX_SETUP(mutex_buf[i]); CRYPTO_set_id_callback(id_function); CRYPTO_set_locking_callback(locking_function); return 1; } int thread_cleanup(void) { int i; if (!mutex_buf) return 0; CRYPTO_set_id_callback(NULL); CRYPTO_set_locking_callback(NULL); for (i = 0; i < CRYPTO_num_locks( ); i++) MUTEX_CLEANUP(mutex_buf[i]); free(mutex_buf); mutex_buf = NULL; return 1; }
我只能回答Qt部分。 使用QThread :: currentThreadId() ,甚至QThread :: currentThread()作为指针值应该是唯一的。
从您链接的OpenSSL文档:
threadid_func(CRYPTO_THREADID *id)
将当前正在执行的线程标识符记录到id中。 这个回调的实现不应该直接填充id,但是如果线程ID是数字的话应该使用CRYPTO_THREADID_set_numeric()
,如果它们是基于指针的话,应该使用CRYPTO_THREADID_set_numeric()
。 如果应用程序没有使用CRYPTO_THREADID_set_callback()
注册这样的回调,那么使用默认的实现 – 在Windows和BeOS上,这使用系统的默认线程标识API,并且在所有其他平台上使用errno的地址。 当且仅当平台具有线程本地错误号码功能时,后者才能满足线程安全的要求。
如图所示,如果您可以提供比OpenSSL的默认实现更好的ID,那么提供您自己的ID实际上是非常有用的。
当您不知道pthread_t
是一个指针还是一个整数时,唯一的提供ID的安全方法是维护您自己的每个线程ID作为线程本地值存储。