This commit is contained in:
qing committed 2026-07-20 11:12:29 +08:00
commit 70d467d052
97 files changed
+10386

No files matched your search

+69
View File
@@ -0,0 +1,69 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Linker files
*.ilk
# Debugger Files
*.pdb
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
*.so.*
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# Build directories
build/
Build/
build-*/
# CMake generated files
CMakeFiles/
CMakeCache.txt
cmake_install.cmake
#Makefile
install_manifest.txt
compile_commands.json
# Temporary files
*.tmp
*.log
*.bak
*.swp
# vcpkg
vcpkg_installed/
# debug information files
*.dwo
# test output & cache
Testing/
.cache/
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 dashun
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+43
View File
@@ -0,0 +1,43 @@
VERSION := 0.0.1
FRAMEWORK_NAME := us
LIB_NAME := libus_th
INSTL_TDIR := /lib
INCLU_TDIR := /usr/include
INCLU_SDIR := inc
CPP := g++
INCS := -I inc
CPPFLAGS := --std=c++20 -O3 -pipe -Wall -Werror
LIBS :=
BUILD_TDIR := build
$(shell mkdir -p $(BUILD_TDIR))
#--------
all: $(BUILD_TDIR)/$(LIB_NAME).so
$(BUILD_TDIR)/$(LIB_NAME).so: $(BUILD_TDIR)/Thread.o
$(CPP) -shared $^ $(LIBS) -o $@
$(BUILD_TDIR)/Thread.o: src/Thread.cpp
$(CPP) $(CPPFLAGS) -fPIC -c $^ $(INCS) -o $@
clear:
@rm -rvf $(BUILD_TDIR)
install:
@echo "install UniServe_libth..."
@mkdir -vp $(INCLU_TDIR)/$(FRAMEWORK_NAME)
@cp -vf $(INCLU_SDIR)/$(FRAMEWORK_NAME)/Cv_wait.hpp $(INCLU_TDIR)/$(FRAMEWORK_NAME)/
@cp -vf $(INCLU_SDIR)/$(FRAMEWORK_NAME)/Fsm.hpp $(INCLU_TDIR)/$(FRAMEWORK_NAME)/
@cp -vf $(INCLU_SDIR)/$(FRAMEWORK_NAME)/ITask.hpp $(INCLU_TDIR)/$(FRAMEWORK_NAME)/
@cp -vf $(INCLU_SDIR)/$(FRAMEWORK_NAME)/Thread.hpp $(INCLU_TDIR)/$(FRAMEWORK_NAME)/
@cp -vf $(BUILD_TDIR)/$(LIB_NAME).so $(INSTL_TDIR)/
@echo "done."
uninstall:
@echo "uninstall UniServe_libth..."
@rm -vf $(INCLU_TDIR)/$(FRAMEWORK_NAME)/Cv_wait.hpp
@rm -vf $(INCLU_TDIR)/$(FRAMEWORK_NAME)/Fsm.hpp
@rm -vf $(INCLU_TDIR)/$(FRAMEWORK_NAME)/ITask.hpp
@rm -vf $(INCLU_TDIR)/$(FRAMEWORK_NAME)/Thread.hpp
@rm -vf $(INSTL_TDIR)/$(LIB_NAME).so
@echo "done."
+14
View File
@@ -0,0 +1,14 @@
# UniServe_libth
UniServe Framework Thread Library.
# Dependancy Chain
It should be C++17.
# Install Method
Use UniServe Generate Installation Script.
``` bash
bash _set.sh
```
# ENJOY!
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
cd "$(dirname "$0")" || exit
make clear
make
make install
+38
View File
@@ -0,0 +1,38 @@
/*
* 利用条件变量进行等待
*
* FIXME: deepseek 认为有一个设计缺陷:它只能用于单次等待-唤醒的场景。
* FIXME: 可能导致永久堵塞,应使用带超时的等待
* FIXME: 使用标准库的 future/promise
*/
#include <thread>
#include <atomic> /* 也许将字段flag创建为原子变量 */
#include <mutex>
#include <condition_variable>
namespace qing {
class Cv_wait { /* 用于等待的条件变量类,对同一个对象进行操作能够阻塞当前线程,或者唤醒被阻塞的线程 */
private:
std::mutex mtx{}; /* 用于控制条件变量的锁 */
std::condition_variable cv{};
bool flag = false; /* 用于解锁条件变量的标志 */
public:
inline void Wait() /* 线程进入等待 */
{
auto lock = std::unique_lock<std::mutex>(mtx);
flag = false;
cv.wait(lock, [this] { return flag; });
}
inline void WakeCv() /* 唤醒线程 */
{
{
std::lock_guard<std::mutex> lcok(mtx);
flag = true;
}
cv.notify_all();
}
};
}
+75
View File
@@ -0,0 +1,75 @@
/*
* 有限状态机(Finite State Machine,FSM)
*/
#pragma once
#include <mutex> /*上锁 使得有限状态机线程安全*/
#include <condition_variable> /*条件变量,使得子类能够等待状态的设置*/
namespace qing {
/*
* FiniteStateMachine有限状态机
*
* 每个数字代表一个状态 使用static_cast<>()之类的函数去赋值
* FIXME: 之前用过一种使用回调函数处理的方式
*/
class Fsm {
public:
/* 状态枚举类 */
enum class Stat: int {
SHUT = -1, /* 关闭 */
STOP = 0, /* 静止 */
START = 1, /* 启动 */
RUNNING = 2 /* 运行 */
/* ... */
};/*Stat*/
/* 以STOP为初始状态 */
Fsm() { set(Stat::STOP); }
enum Stat check() { /* 检查当前的状态 */
std::lock_guard<std::mutex> lk(mtx);
return stat;
} /*check*/
/*
* 在不上锁的情况下设置一个状态
* 这里不能使用锁,因为我们还要在临界区里唤醒条件变量
*/
void set_without_lock(Stat stat) { this->stat = stat; }
/* 带锁的状态设置 但是该方法不唤醒条件变量 */
void set_without_notify(Stat stat) {
std::lock_guard<std::mutex> lk(mtx);
this->stat = stat;
}
/* 带锁和条件唤醒的状态设置 */
void set(Stat stat) {
{
std::lock_guard<std::mutex> lk(mtx);
set_without_lock(stat);
ready = true;
}
cv.notify_all();
}
//protected:
void suspend() { /* 阻塞线程,等待事件唤醒 */
std::unique_lock<std::mutex> lk(mtx);
ready = false;
cv.wait(lk, [this] { return ready; });
}/*suspend */
private:
std::mutex mtx; /* 线程安全 */
bool ready = false; /* 用于条件变量的阻塞唤醒 */
std::condition_variable cv; /* 条件变量 阻塞/唤醒线程 */
enum Stat stat; /* 状态机的状态变量 */
};//Fsm
}//qing
+9
View File
@@ -0,0 +1,9 @@
#pragma once
namespace qing{
class ITask { /* 单个任务通用接口 */
public:
virtual void start() = 0; /* 任务开始 */
virtual void stop() = 0; /* 任务结束 */
virtual bool isRunning() = 0; /* 是否在跑 */
};
}
+149
View File
@@ -0,0 +1,149 @@
/* 线程
*
*
* 包含一个简易的多线程控制机制,需要共享的变量和函数声明为成员。
*
* 线程主函数包括了流程控制,要使用需要实现其中的各个事件方法
*
* 20250621: 从派生改为持有
*
* NOTE: 在对象构造完之后应该激活
*/
#pragma once
#include <thread>
#include <memory> /* 内存管理 */
#include <chrono> /* 用于线程休息 */
#include <iostream>
#include <stdexcept>
#include <functional>
#include "us/Fsm.hpp" /* 有限状态机 */
namespace qing {
class Thread;
//using f_t = void(*)(Thread&);
using f_t = std::function<void(Thread&)>;
class Thread {
public:
/* 作为可变的函数,持有回调可能比继承更好
*
* FIXME: 可以改为链式传递参数 */
//Thread(f_t stop_callback, f_t wake_callback, f_t loop_callback, f_t clear_callback);
/* 使用默认初始化方法,然后用几个函数分别进行回调初始化 */
Thread() = default;
/*
* 删除复制构造函数。
*
* 因为持有线程类,不要轻举妄动。
*/
Thread(const Thread&) = delete;
/*
* 虚析构函数
*
* FIXME: 具体有什么用,忘了
*/
virtual ~Thread() {}
/* 设置停止回调函数 */
void set_stop(f_t callback);
/* 设置唤醒回调函数 */
void set_wake(f_t callback);
/* 设置循环体回调函数 */
void set_loop(f_t callback);
/* 设置清理回调函数 */
void set_clear(f_t callback);
/*-----------------------------------*/
/*-----------------------------------*/
/*
* 检查状态的方法
*
* NOTE: 做成虚函数,万一子类有特别要求呢
*
* FIXME: 将检查器和变异器做成一个简单的回调函数
*/
Fsm::Stat check();
/*-----------------------------------*/
/*-----------------------------------*/
/* 让线程能够阻塞直到新的状态被赋予的方法 */
void suspend();
/*-----------------------------------*/
/*-----------------------------------*/
/* 状态改变的方法 - 变异器 */
/* 进入唤醒状态
*
* 唤醒函数不可以进行该类中的锁操作,否则会造成死锁
*/
void wake();
/* 进入静止状态
*
* 上锁、唤醒阻塞的线程
*/
void stop();
/* 进入关闭状态 */
void shut();
/* 进入运行状态 */
void run();
/*-----------------------------------*/
/*-----------------------------------*/
/*
* 激活线程,申请线程对象
*
* 该函数不能放在构造函数内,因为需要确保对象已经被构造了
*/
void Activate();
/*
* 尝试唤醒线程并等待它开始 据说该函数有问题可能导致异常
*/
void WaitStart();
/* 等待线程关闭 */
void WaitClose();
/*-----------------------------------*/
/* 线程主函数 */
void main();
private:
qing::Fsm fsm{}; /* 持有状态机类型 */
std::unique_ptr<std::thread> th; /* 持有线程类型 */
std::mutex mtx_th; /* 持有锁类型 */
/*
* 这里持有一个条件变量,用于阻塞以等待线程的关闭
*
* 注意状态机中的cv是另一个变量
*/
std::condition_variable cv;
/* 辅助条件变量的逻辑型 */
bool ready;
/* 事件回调 */
std::unique_ptr<f_t> StopEvent;
std::unique_ptr<f_t> WakeEvent;
std::unique_ptr<f_t> LoopEvent;
std::unique_ptr<f_t> ClearEvent;
};
}
+140
View File
@@ -0,0 +1,140 @@
#include "us/Thread.hpp"
namespace qing{
//Thread::Thread(f_t stop_callback, f_t wake_callback, f_t loop_callback, f_t clear_callback)
//{
// StopEvent = std::make_unique<f_t>(stop_callback);
// WakeEvent = std::make_unique<f_t>(wake_callback);
// LoopEvent = std::make_unique<f_t>(loop_callback);
// ClearEvent = std::make_unique<f_t>(clear_callback);
//};
void Thread::set_stop(f_t callback) {
StopEvent = std::make_unique<f_t> (callback);
}
void Thread::set_wake(f_t callback) {
WakeEvent = std::make_unique<f_t> (callback);
}
void Thread::set_loop(f_t callback) {
LoopEvent = std::make_unique<f_t> (callback);
}
void Thread::set_clear(f_t callback) {
ClearEvent = std::make_unique<f_t> (callback);
}
Fsm::Stat Thread::check() {
return fsm.check();
}
void Thread::suspend() {
fsm.suspend();
}
/* 唤醒函数不可以进行该类中的锁操作,否则会造成死锁 */
void Thread::wake() {
//{
//std::lock_guard<std::mutex> lk(mtx_th);
fsm.set(Fsm::Stat::START);
//ready = true;
//}
//cv.notify_all();
} /* wake */
/* 上锁、唤醒阻塞的线程 */
void Thread::stop() {
{
std::lock_guard<std::mutex> lk(mtx_th);
fsm.set(Fsm::Stat::STOP);
ready = true;
}
/* 可能会出现多个线程在等待的情况 */
cv.notify_all();
}/* stop */
void Thread::shut() {
{
std::lock_guard<std::mutex> lk(mtx_th);
fsm.set(Fsm::Stat::SHUT);
ready = true;
}
cv.notify_all();
} /*shut*/
void Thread::run() {
{
std::lock_guard<std::mutex> lk(mtx_th);
fsm.set(Fsm::Stat::RUNNING);
ready = true;
}
cv.notify_all();
}/*run*/
void Thread::Activate() {
/* 防止重复初始化
* FIXME: 抛出异常?感觉也不太合适 */
if (th) return;
/* 申请线程资源 */
th = std::make_unique<std::thread>(&Thread::main, this);
}
void Thread::WaitStart() {
std::unique_lock<std::mutex> lk(mtx_th); /* 不进入临界区可能会造成死等,在唤醒过程非常短暂的情况下 */
wake(); /* 这就是为什么wake()不可以获取临界区,否则会造成死锁 */
ready = false; /* 这个临界区结束后,WakeEvent()中的run()会唤醒线程的堵塞 */
cv.wait(lk, [this] { return ready; });
}
void Thread::WaitClose() {
shut();
if (th->joinable())
th->join();
}
/* 线程主函数 */
void Thread::main() {
/* 回字形循环 */
while (check() != Fsm::Stat::SHUT) {
try { /* 异常只会使线程静止 */
//------------------------------------------------
while (check() == Fsm::Stat::STOP) {
(*StopEvent)(*this); /* 静止状态 */
}
if (check() == Fsm::Stat::START) {
//(*ClearEvent)(*this); /* 在开始之前做一次清理 */
(*WakeEvent)(*this); /* 开始事件 */
}
while (check() == Fsm::Stat::RUNNING) {
(*LoopEvent)(*this); /* 从设置阶段进入运行态 */
}
/* 清理事件 (记得检查成员变量有没有被设置) */
(*ClearEvent)(*this);
//------------------------------------------------
}
catch (std::exception& exp) {
std::cout << "Thread throw a exception: " << exp.what() << std::endl;
stop(); /* 因为这里的停止,线程在循环内抛出异常进程不会死亡,所以需要特别注意内存泄漏 */
}
}
}
}