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:
1 parent
f214c862d3
commit
4506601773
2 files changed
+195
-10
No files matched your search
+194
-9
@@ -1,14 +1,199 @@
|
|||||||
# UniServe_libth
|
# libth — UniServe 线程库
|
||||||
UniServe Framework Thread Library.
|
|
||||||
|
|
||||||
# Dependancy Chain
|
C++20 轻量级多线程控制库,为 UniServe Framework 提供线程抽象与状态机驱动的执行模型。由 `core`(PMC 进程管理器)的 `HttpTask` 和 `ProcessTask` 直接依赖。
|
||||||
It should be C++17.
|
|
||||||
|
|
||||||
# Install Method
|
命名空间 `qing`,库文件 `libus_th.so`,头文件安装至 `/usr/include/us/`。
|
||||||
Use UniServe Generate Installation Script.
|
|
||||||
|
|
||||||
``` 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
|
||||||
@@ -28,7 +28,7 @@ public:
|
|||||||
inline void WakeCv() /* 唤醒线程 */
|
inline void WakeCv() /* 唤醒线程 */
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lcok(mtx);
|
std::lock_guard<std::mutex> lock(mtx);
|
||||||
flag = true;
|
flag = true;
|
||||||
}
|
}
|
||||||
cv.notify_all();
|
cv.notify_all();
|
||||||
|
|||||||
Reference in new issue
Block a user