您的位置:首页 > 其它

libuv学习笔记(23)

2016-07-02 14:32 302 查看

libuv学习笔记(23)

线程相关数据结构与函数(1)

数据结构

typedef HANDLE uv_thread_t;//就是句柄


typedef struct {//线程局部变量使用
DWORD tls_index;
} uv_key_t;


typedef struct uv_once_s {//libuv用此结构保证某一函数只执行一次
unsigned char ran;
HANDLE event;
} uv_once_t;


typedef CRITICAL_SECTION uv_mutex_t;//通过临界区实现互斥量


线程相关API

创建线程

int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
struct thread_ctx* ctx;
int err;
HANDLE thread;
ctx = uv__malloc(sizeof(*ctx));//将在uv__thread_start中释放
if (ctx == NULL)
return UV_ENOMEM;
ctx->entry = entry;
ctx->arg = arg;
//创建线程
thread = (HANDLE) _beginthreadex(NULL,
0,
uv__thread_start,
ctx,
CREATE_SUSPENDED,
NULL);
if (thread == NULL) {
err = errno;
uv__free(ctx);
} else {
err = 0;
*tid = thread;
ctx->self = thread;
ResumeThread(thread);
}

switch (err) {
case 0:
return 0;
case EACCES:
return UV_EACCES;
case EAGAIN:
return UV_EAGAIN;
case EINVAL:
return UV_EINVAL;
}
return UV_EIO;
}


新线程调用的函数

static UINT __stdcall uv__thread_start(void* arg) {
struct thread_ctx *ctx_p;
struct thread_ctx ctx;
ctx_p = arg;
ctx = *ctx_p;
uv__free(ctx_p);//释放
//调用uv_key_create初始化TLS  key   uv__current_thread_key
uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
//将本线程的句柄存入线程本地存储,通过uv__current_thread_key标识
uv_key_set(&uv__current_thread_key, (void*) ctx.self);
ctx.entry(ctx.arg);//调用真正的任务函数
return 0;
}


获取线程句柄,需要在线程中调用,该线程通过uv_thread_create创建

uv_thread_t uv_thread_self(void) {
uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
return (uv_thread_t) uv_key_get(&uv__current_thread_key);
}


等待线程执行完成

int uv_thread_join(uv_thread_t *tid) {
if (WaitForSingleObject(*tid, INFINITE))
return uv_translate_sys_error(GetLastError());
else {
CloseHandle(*tid);
*tid = 0;
return 0;
}
}


线程本地存储

创建TLS key,注意线程本地存储大小有限,本函数可能会失败,无法创建更多的本地存储

int uv_key_create(uv_key_t* key) {
key->tls_index = TlsAlloc();
if (key->tls_index == TLS_OUT_OF_INDEXES)
return UV_ENOMEM;
return 0;
}


释放线程本地存储变量

void uv_key_delete(uv_key_t* key) {
if (TlsFree(key->tls_index) == FALSE)
abort();
key->tls_index = TLS_OUT_OF_INDEXES;
}


获取线程本地存储变量

void* uv_key_get(uv_key_t* key) {
void* value;
value = TlsGetValue(key->tls_index);//调用API
if (value == NULL)
if (GetLastError() != ERROR_SUCCESS)
abort();
return value;
}


设置线程本地存储变量

void uv_key_set(uv_key_t* key, void* value) {
if (TlsSetValue(key->tls_index, value) == FALSE)//TLS API
abort();
}


只运行一次的方法,通过uv_once_t标识

void uv_once(uv_once_t* guard, void (*callback)(void)) {
if (guard->ran) {//如果正在运行,返回
return;
}
uv__once_inner(guard, callback);
}


static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
DWORD result;
HANDLE existing_event, created_event;
created_event = CreateEvent(NULL, 1, 0, NULL);//创建事件句柄
if (created_event == 0) {
uv_fatal_error(GetLastError(), "CreateEvent");
}
//原子改变变量的值,并返回原来的值
existing_event = InterlockedCompareExchangePointer(&guard->event,
created_event,
NULL);
//如果existing_event 原来为空,表示是第一次执行
if (existing_event == NULL) {
callback();//调用回调
result = SetEvent(created_event);//改变event状态
assert(result);
guard->ran = 1;//已经运行,修改表计量
} else {
//并不是第一次,说明有线程通过相同的uv_once_t在本线程之前调用了uv_once
CloseHandle(created_event);
//等待直到先运行的线程调用回调函数执行完成
result = WaitForSingleObject(existing_event, INFINITE);
assert(result == WAIT_OBJECT_0);
}
}


互斥锁相关函数

初始化

int uv_mutex_init(uv_mutex_t* mutex) {
InitializeCriticalSection(mutex);//初始化临界区
return 0;
}


释放互斥锁

void uv_mutex_destroy(uv_mutex_t* mutex) {
DeleteCriticalSection(mutex);//释放临界区
}


锁定

void uv_mutex_lock(uv_mutex_t* mutex) {
EnterCriticalSection(mutex);//进入临界区
}


尝试锁定

int uv_mutex_trylock(uv_mutex_t* mutex) {
if (TryEnterCriticalSection(mutex))//尝试进入临界区
return 0;
else
return UV_EBUSY;
}


解锁

void uv_mutex_unlock(uv_mutex_t* mutex) {
LeaveCriticalSection(mutex);//离开临界区
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  libuv 线程 mutex TLS uv-once