这个文件内是针对windows平台的线程实现。在VisualStudio内可以看到,socket_openssl.c、socket_unix.c、thread_fork.c和thread_pthread.c这四个文件在abyss工程生成时不会生成代码。这很好理解,尤其是thread_fork.c和thread_pthread.c这两个文件,再加上thread_windows.c文件,就可以理解成在windows平台下编译abyss只使用windows平台下线程相关的特定代码。
线程
struct abyss_thread {
HANDLE handle;
void * userHandle;
TThreadProc * func;
TThreadDoneFn * threadDone;
};
typedef struct abyss_thread TThread;
TThread是库内部针对线程的封装。ThreadCreate函数的作用就是创建一个TThread结构体变量,并启动一个线程。TThread结构体变量将提供给线程主函数。用户代码想向线程提供任何自定义的数据可以将其放置在userHandle中。用户代码中的线程主函数必须是TThreadProc类型。同时,用户代码还可以提供一个TThreadDoneFn类型的线程完成处理函数。useSigchld参数可能在windows平台下无意义,所以没有使用它。注意到线程被创建后不会立即启动,因为使用了CREATE_SUSPENDED参数。线程创建完毕后句柄保存在TThread变量的handle属性内。
void
ThreadCreate(TThread ** const threadPP,
void * const userHandle,
TThreadProc * const func,
TThreadDoneFn * const threadDone,
bool const useSigchld,
const char ** const errorP) {
TThread * threadP;
MALLOCVAR(threadP);
if (threadP == NULL)
xmlrpc_asprintf(errorP,
"Can't allocate memory for thread descriptor.");
else {
DWORD z;
threadP->userHandle = userHandle;
threadP->func = func;
threadP->threadDone = threadDone;
threadP->handle = (HANDLE)_beginthreadex(NULL,
THREAD_STACK_SIZE,
threadRun,
threadP,
CREATE_SUSPENDED,
&z);
if (threadP->handle == NULL)
xmlrpc_asprintf(errorP, "_beginthreadex() failed.");
else {
*errorP = NULL;
*threadPP = threadP;
}
if (*errorP)
free(threadP);
}
}
static uint32_t WINAPI
threadRun(void * const arg) {
struct abyss_thread * const threadP = arg;
threadP->func(threadP->userHandle);
threadP->threadDone(threadP->userHandle);
return 0;
}
由于TThread中保存了线程句柄,所以其他所有线程封装函数均针对TThread的handle句柄进行操作。
Mutex
struct abyss_mutex {
HANDLE winMutex;
};
typedef struct abyss_mutex TMutex;
abyss_mutex在windows平台下只是封装了一个句柄。MutexCreate函数处理过程也说明了这点。申请空间创建好TMutex后,接着只是调用CreateMutex函数创建windows平台下的mutex对象,成功后将句柄赋给TMutex的winMutex属性。其他Mutex函数就像线程函数一样,都只是针对Mutex句柄进行操作。
bool
MutexCreate(TMutex ** const mutexPP) {
TMutex * mutexP;
bool succeeded;
MALLOCVAR(mutexP);
if (mutexP) {
mutexP->winMutex = CreateMutex(NULL, FALSE, NULL);
succeeded = (mutexP->winMutex != NULL);
} else
succeeded = FALSE;
if (!succeeded)
free(mutexP);
*mutexPP = mutexP;
TraceMsg( "Created Mutex %s\n", (succeeded ? "ok" : "FAILED") );
return succeeded;
}