eduwin 线程模块 API
头文件:
eduwin_thread.h(或通过eduwin.h统一引用)
封装 Win32 线程创建、互斥锁、线程安全 UI 更新。核心亮点:execute_on_main() 隐藏了 PostMessage + 隐藏窗口调度的细节,任意线程中调用即可安全更新 UI。
初始化 / 清理
int thread_init(void);
void thread_cleanup(void);
thread_init() 必须在 init_app() 之后调用(因为内部需要消息循环)。thread_cleanup() 在 run_app() 返回后调用。
init_app();
thread_init();
// ... 创建窗口、启动线程 ...
run_app();
thread_cleanup();
线程创建
typedef void (*thread_func_t)(void *arg);
typedef struct thread_s thread_t;
thread_t* thread_run(thread_func_t func, void *arg);
int thread_join(thread_t *t, int timeout_ms);
void thread_detach(thread_t *t);
DWORD thread_self_id(void);
void thread_sleep(int ms);
thread_run 启动一个新线程。线程签名简化为 void func(void*),无需 DWORD WINAPI 模板代码。
thread_join 的 timeout_ms:-1 无限等待,0 不等待,>0 等待指定毫秒数。返回 0 表示线程已结束,-1 表示超时。
thread_detach 分离线程,线程结束后自动释放资源。
void my_worker(void *arg) {
thread_sleep(1000);
// 做点事...
}
thread_t *t = thread_run(my_worker, NULL);
// ... 干别的 ...
thread_join(t, 5000); // 等最多5秒
thread_detach(t); // 释放资源
线程安全 UI 更新
void execute_on_main(HWND hwnd, void (*cb)(void *), void *arg);
可在任意线程中调用。 cb(arg) 会在主线程的消息循环中被执行。如果调用时已经位于主线程,直接执行不走队列。
工作原理:
子线程 ──→ execute_on_main(hwnd, callback, arg)
↓ 打包为 main_call_t
↓ PostMessage
隐藏 dispatch 窗口 ──→ WM_DISPATCH_CALL ──→ 主线程执行 callback(arg)
无需子类化窗口过程,无需自定义 WM_USER 消息号。
static void on_log(void *msg) {
llog((const WCHAR*)msg);
free(msg);
}
void my_thread(void *arg) {
execute_on_main(g_win, on_log, _wcsdup(L"线程更新了 UI"));
}
互斥锁
typedef struct mutex_s mutex_t;
mutex_t* mutex_create(void);
void mutex_lock(mutex_t *m);
int mutex_trylock(mutex_t *m); // 0=锁定成功
void mutex_unlock(mutex_t *m);
void mutex_free(mutex_t *m);
基于 CRITICAL_SECTION(用户态锁,无内核切换,比 Windows Mutex 对象轻量)。
static int g_counter = 0;
static mutex_t *g_mutex = NULL;
void counter_thread(void *arg) {
mutex_lock(g_mutex);
g_counter++;
mutex_unlock(g_mutex);
}
int main(void) {
thread_init();
g_mutex = mutex_create();
// ... 启动若干线程 ...
mutex_free(g_mutex);
thread_cleanup();
}
完整示例
参见 samples/thread_demo/(3 个并发线程 + 互斥锁计数器 + execute_on_main 更新 UI)。