init
This commit is contained in:
commit
70d467d052
97 files changed
+10386
No files matched your search
@@ -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/
|
||||
@@ -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.
|
||||
@@ -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."
|
||||
@@ -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!
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
cd "$(dirname "$0")" || exit
|
||||
make clear
|
||||
make
|
||||
make install
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
namespace qing{
|
||||
class ITask { /* 单个任务通用接口 */
|
||||
public:
|
||||
virtual void start() = 0; /* 任务开始 */
|
||||
virtual void stop() = 0; /* 任务结束 */
|
||||
virtual bool isRunning() = 0; /* 是否在跑 */
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
}
|
||||
@@ -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(); /* 因为这里的停止,线程在循环内抛出异常进程不会死亡,所以需要特别注意内存泄漏 */
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user