docs(libth): 完整的 README 文档,覆盖 API、架构、构建与使用示例

- 新增 4 个类的完整 API 说明(Thread/Fsm/ITask/Cv_wait)
- "回字形"执行循环和两阶段构造的设计说明
- 构建、安装、链接、卸载的完整指引
- 可运行的使用示例代码
- 设计要点与注意事项(死锁风险、单次使用限制等)
- 修正 C++ 标准版本为 C++20(与 Makefile 一致)

fix(libth): Cv_wait.hpp 中 lcok 拼写错误修正为 lock
This commit is contained in:
qing committed 2026-07-30 11:58:26 +08:00
1 parent f214c862d3
commit 4506601773
2 files changed
+195 -10

No files matched your search

+194 -9
View File
@@ -1,14 +1,199 @@
# UniServe_libth
UniServe Framework Thread Library.
# libth — UniServe 线程库
# Dependancy Chain
It should be C++17.
C++20 轻量级多线程控制库,为 UniServe Framework 提供线程抽象与状态机驱动的执行模型。由 `core`(PMC 进程管理器)的 `HttpTask` 和 `ProcessTask` 直接依赖。
# Install Method
Use UniServe Generate Installation Script.
命名空间 `qing`,库文件 `libus_th.so`,头文件安装至 `/usr/include/us/`。
``` bash
bash _set.sh
## 架构
```
┌──────────┐ ┌───────────────────────────────┐
│ ITask │ │ Thread │
│ (接口) │ │ 持有 Fsm + std::thread │
│ start() │ │ │
│ stop() │ │ set_stop / set_wake / │
│ isRunning│ │ set_loop / set_clear │
└────┬─────┘ │ Activate / WaitStart / │
│ 实现 │ WaitClose │
▼ │ │
HttpTask │ main(): "回字形" 执行循环 │
ProcessTask └──────────────┬────────────────┘
(位于 core) │ 持有
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌──────────┐ ┌────────────┐ ┌──────────┐
│ Fsm │ │ Cv_wait │ │ Thread │
│ 状态机 │ │ 条件等待 │ │ .cpp │
│ SHUT/STOP│ │ Wait() │ │ 实现文件 │
│ START/ │ │ WakeCv() │ │ │
│ RUNNING │ │ │ │ │
└──────────┘ └────────────┘ └──────────┘
```
# ENJOY!
## 类与 API
### ITask — 任务接口
纯虚基类,定义可运行任务的契约。下游模块(core 中的 HttpTask、ProcessTask)继承实现。
```cpp
class ITask {
virtual void start() = 0; // 启动任务
virtual void stop() = 0; // 停止任务
virtual bool isRunning() = 0; // 查询运行状态
};
```
### Fsm — 线程安全有限状态机
4 个状态:`SHUT(-1)` → `STOP(0)` → `START(1)` → `RUNNING(2)`。Thread 通过 Fsm 驱动其执行流程。
| 方法 | 说明 |
|------|------|
| `check()` | 线程安全地读取当前状态 |
| `set(Stat)` | 加锁设置状态 + 唤醒阻塞线程 |
| `set_without_lock(Stat)` | 不加锁设置(用于临界区内) |
| `set_without_notify(Stat)` | 加锁但不唤醒条件变量 |
| `suspend()` | 阻塞当前线程直至状态变更 |
初始状态为 `STOP`。
### Thread — 线程抽象
基于回调组合(composition over inheritance),持有 `Fsm` 和 `std::thread`。执行模型为"回字形"循环:
```
while (状态 != SHUT) {
① STOP: 循环调用 StopEvent 回调(空闲轮询)
② START: 单次调用 WakeEvent 回调(启动)
③ RUNNING:循环调用 LoopEvent 回调(工作循环)
④ 退出后: 调用 ClearEvent 回调(清理)
}
异常捕获:loop 内抛出 std::exception 自动回退到 STOP,进程不崩溃。
```
**生命周期:两阶段构造。** 构造函数只初始化成员,`Activate()` 才真正创建 `std::thread`——避免线程在对象构造完成前启动的竞态条件。
| 方法 | 说明 |
|------|------|
| `set_stop(f_t)` | 设置 STOP 状态回调 |
| `set_wake(f_t)` | 设置 START 状态回调 |
| `set_loop(f_t)` | 设置 RUNNING 状态回调 |
| `set_clear(f_t)` | 设置清理回调 |
| `Activate()` | 创建 std::thread 并启动 main() |
| `WaitStart()` | 唤醒线程并阻塞至其进入 RUNNING |
| `WaitClose()` | 关闭线程并 join 等待退出 |
| `wake()` | 状态 → START(不可持有锁,否则死锁) |
| `stop()` | 状态 → STOP |
| `shut()` | 状态 → SHUT |
| `run()` | 状态 → RUNNING |
| `check()` | 查询当前状态 |
| `suspend()` | 阻塞等待状态变更 |
回调类型:`using f_t = std::function<void(Thread&)>;`
### Cv_wait — 条件变量等待工具
简单的单次等待-唤醒工具,用于线程间同步。
| 方法 | 说明 |
|------|------|
| `Wait()` | 阻塞当前线程至 WakeCv() 被调用 |
| `WakeCv()` | 唤醒所有等待线程 |
> **已知限制**:仅支持单次等待-唤醒周期,不可复用。缺少超时机制,可能永久阻塞。代码中标注建议改用 `std::future`/`std::promise`。core 的 `main.cpp` 使用此类。
## 构建与安装
```bash
# 一键构建 + 安装(需 sudo)
bash _set.sh
# 或手动执行
make # 编译 libus_th.so
make install # 安装头文件到 /usr/include/us/ + .so 到 /lib/
make uninstall # 卸载
make clear # 清理构建产物
```
安装后使用:
```cpp
#include <us/Thread.hpp>
#include <us/Fsm.hpp>
#include <us/ITask.hpp>
#include <us/Cv_wait.hpp>
```
链接:`g++ -std=c++20 ... -lus_th`
## 使用示例
```cpp
#include <us/Thread.hpp>
#include <iostream>
int main() {
qing::Thread worker;
bool done = false;
// STOP 状态回调:空闲等待
worker.set_stop([&](qing::Thread& t) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
});
// START 状态回调:一次性初始化
worker.set_wake([&](qing::Thread& t) {
std::cout << "worker started" << std::endl;
t.run(); // 进入 RUNNING
});
// RUNNING 状态回调:工作循环
worker.set_loop([&](qing::Thread& t) {
std::cout << "working..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
done = true;
t.stop(); // 回到 STOP
});
// 清理回调
worker.set_clear([](qing::Thread& t) {
std::cout << "cycle cleaned up" << std::endl;
});
worker.Activate();
worker.WaitStart(); // 阻塞至 RUNNING
while (!done) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
worker.WaitClose();
return 0;
}
```
## 依赖
- C++20(`g++ --std=c++20`)
- 纯标准库,无第三方依赖
- 线程库需链接 `-pthread`
## 设计要点
- **回调组合优于继承**。2025 年 6 月从派生改为持有 `std::function` 回调,Thread 不再需要子类化。
- **两阶段构造**。构造与 `Activate()` 分离,防止 `std::thread` 在对象构造完成前访问未初始化的成员。
- **异常安全**。main() 循环捕获 `std::exception` 后回退到 STOP 而非崩溃。注意:catch 后继续运行可能造成内存泄漏。
- **wake() 不可加锁**。`WaitStart()` 先持有 `mtx_th` 再调用 `wake()`,若 `wake()` 内部也尝试获取同一锁会造成死锁。
- **Fsm 提供两套条件变量**。Fsm 内部有一套 `cv` 用于 `suspend()`,Thread 自身另有一套 `cv` 用于 `WaitStart()`/`WaitClose()`,互不干扰。
## 注意事项
- Cv_wait 仅支持单次使用,复用时 `flag` 残留为 `true` 会导致 `Wait()` 立即返回而不阻塞。
- Fsm 的 `suspend()` 等待的是 Fsm 内部的 `ready` 标志,由 `set()` 触发;Thread 的 `WaitStart()` 等待的是 Thread 内部的 `ready`,由 `run()`/`stop()`/`shut()` 触发。两者独立。
- `Activate()` 不可重复调用(内部有空指针检查),但不会报错,静默返回。
- 析构函数为虚函数,允许安全的多态删除。
## 许可证
MIT License
+1 -1
View File
@@ -28,7 +28,7 @@ public:
inline void WakeCv() /* 唤醒线程 */
{
{
std::lock_guard<std::mutex> lcok(mtx);
std::lock_guard<std::mutex> lock(mtx);
flag = true;
}
cv.notify_all();