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_jointimeout_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)。