# eduwin 线程模块 API

> 头文件：`eduwin_thread.h`（或通过 `eduwin.h` 统一引用）

封装 Win32 线程创建、互斥锁、线程安全 UI 更新。**核心亮点：`execute_on_main()`** 隐藏了 `PostMessage` + 隐藏窗口调度的细节，任意线程中调用即可安全更新 UI。

## 初始化 / 清理

```c
int  thread_init(void);
void thread_cleanup(void);
```

`thread_init()` 必须在 `init_app()` 之后调用（因为内部需要消息循环）。`thread_cleanup()` 在 `run_app()` 返回后调用。

```c
init_app();
thread_init();
// ... 创建窗口、启动线程 ...
run_app();
thread_cleanup();
```

## 线程创建

```c
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` 分离线程，线程结束后自动释放资源。

```c
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 更新

```c
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` 消息号。

```c
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"));
}
```

## 互斥锁

```c
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 对象轻量）。

```c
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）。
