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);//离开临界区 }
相关文章推荐
- C#线程间不能调用剪切板的解决方法
- C#线程同步的三类情景分析
- C#获取进程或线程相关信息的方法
- 简单对比C#程序中的单线程与多线程设计
- C#停止线程的方法
- C#子线程更新UI控件的方法实例总结
- C#线程队列用法实例分析
- C++使用CriticalSection实现线程同步实例
- 基于C++实现的线程休眠代码
- VB读取线程、句柄及写入内存的API代码实例
- C#网络编程基础之进程和线程详解
- C#通过Semaphore类控制线程队列的方法
- C#多线程处理多个队列数据的方法
- C#实现线程安全的简易日志记录方法
- C#中线程同步对象的方法分析
- C#中Mutex对象用法分析
- ASP.NET线程相关配置
- 浅析linux环境下一个进程最多能有多少个线程
- 再谈JavaScript线程