├── .gitattributes
├── .github
└── workflows
│ ├── cmake4mac.yml
│ ├── cmake4ubuntu.yml
│ └── cmake4win.yml
├── .gitignore
├── CMakeLists.txt
├── MyFunction.h
├── README.md
├── cmake
└── CThreadPool-env-include.cmake
├── doc
└── image
│ └── CThreadPool Author.jpg
├── src
├── CBasic
│ ├── CBasicDefine.h
│ ├── CBasicInclude.h
│ ├── CDescInfo.h
│ ├── CException.h
│ ├── CFuncType.h
│ ├── CObject.h
│ ├── CStatus.h
│ ├── CStdEx.h
│ ├── CStrDefine.h
│ ├── CStruct.h
│ └── CValType.h
├── CThreadPool.h
└── UtilsCtrl
│ ├── ThreadPool
│ ├── Lock
│ │ ├── ULockInclude.h
│ │ └── USpinLock.h
│ ├── Queue
│ │ ├── UAtomicPriorityQueue.h
│ │ ├── UAtomicQueue.h
│ │ ├── UAtomicRingBufferQueue.h
│ │ ├── ULockFreeRingBufferQueue.h
│ │ ├── UQueueDefine.h
│ │ ├── UQueueInclude.h
│ │ ├── UQueueObject.h
│ │ └── UWorkStealingQueue.h
│ ├── Semaphore
│ │ └── USemaphore.h
│ ├── Task
│ │ ├── UTask.h
│ │ ├── UTaskGroup.h
│ │ └── UTaskInclude.h
│ ├── Thread
│ │ ├── UThreadBase.h
│ │ ├── UThreadInclude.h
│ │ ├── UThreadPrimary.h
│ │ └── UThreadSecondary.h
│ ├── UThreadObject.h
│ ├── UThreadPool.h
│ ├── UThreadPool.inl
│ ├── UThreadPoolConfig.h
│ ├── UThreadPoolDefine.h
│ └── UThreadPoolInclude.h
│ ├── UAllocator.h
│ ├── UtilsDefine.h
│ ├── UtilsFunction.h
│ ├── UtilsInclude.h
│ └── UtilsObject.h
└── tutorial.cpp
/.gitattributes:
--------------------------------------------------------------------------------
1 | # To shield the difference between Windows and Linux systems.
2 |
3 | *.h text eol=native
4 | *.cpp text eol=native
5 | *.inl text eol=native
--------------------------------------------------------------------------------
/.github/workflows/cmake4mac.yml:
--------------------------------------------------------------------------------
1 | name: CMake4Mac
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | env:
10 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
11 | BUILD_TYPE: Release
12 |
13 | jobs:
14 | build:
15 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
16 | # You can convert this to a matrix build if you need cross-platform coverage.
17 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
18 | runs-on: macos-latest
19 |
20 | steps:
21 | - uses: actions/checkout@v2
22 |
23 | - name: Configure CMake
24 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
25 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
26 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
27 |
28 | - name: Build
29 | # Build your program with the given configuration
30 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
31 |
--------------------------------------------------------------------------------
/.github/workflows/cmake4ubuntu.yml:
--------------------------------------------------------------------------------
1 | name: CMake4Ubuntu
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | env:
10 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
11 | BUILD_TYPE: Release
12 |
13 | jobs:
14 | build:
15 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
16 | # You can convert this to a matrix build if you need cross-platform coverage.
17 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
18 | runs-on: ubuntu-latest
19 |
20 | steps:
21 | - uses: actions/checkout@v2
22 |
23 | - name: Configure CMake
24 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
25 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
26 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
27 |
28 | - name: Build
29 | # Build your program with the given configuration
30 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
31 |
--------------------------------------------------------------------------------
/.github/workflows/cmake4win.yml:
--------------------------------------------------------------------------------
1 | name: CMake4Win
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | env:
10 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
11 | BUILD_TYPE: Release
12 |
13 | jobs:
14 | build:
15 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
16 | # You can convert this to a matrix build if you need cross-platform coverage.
17 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
18 | runs-on: windows-latest
19 |
20 | steps:
21 | - uses: actions/checkout@v2
22 |
23 | - name: Configure CMake
24 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
25 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
26 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
27 |
28 | - name: Build
29 | # Build your program with the given configuration
30 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /cmake-build-debug/
2 | /cmake-build-release/
3 | /.idea/
4 | .DS_Store
5 | build*/
6 | .vscode/
7 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | message("* * * * * * * * * * * * * * * * *")
2 | message("* _____ _______ _____ *")
3 | message("* / ____| |__ __| | __ \\ *")
4 | message("* | | | | | |__) | *")
5 | message("* | | | | | ___/ *")
6 | message("* | |____ | | | | *")
7 | message("* \\_____| |_| |_| *")
8 | message("* * * * * * * * * * * * * * * * *")
9 |
10 | cmake_minimum_required(VERSION 3.5.0)
11 |
12 | project(CThreadPool VERSION 1.3.0)
13 |
14 | set(CMAKE_CXX_STANDARD 11)
15 |
16 | # add CThreadPool environment info
17 | include(cmake/CThreadPool-env-include.cmake)
18 |
19 | # 如果开启此宏定义,则CGraph执行过程中,不会在控制台打印任何信息
20 | # add_definitions(-D_CGRAPH_SILENCE_)
21 |
22 | # 编译libCThreadPool动态库
23 | # add_library(CThreadPool SHARED ${CTP_SRC_LIST})
24 |
25 | # 编译libCThreadPool静态库
26 | # add_library(CThreadPool STATIC ${CTP_SRC_LIST})
27 |
28 | add_executable(tutorial
29 | ${CTP_SRC_LIST}
30 | tutorial.cpp)
31 |
--------------------------------------------------------------------------------
/MyFunction.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: MyFunction.h
5 | @Time: 2021/9/2 11:20 下午
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_MYFUNCTION_H
10 | #define CGRAPH_MYFUNCTION_H
11 |
12 |
13 | int add(int i, int j) {
14 | return i + j;
15 | }
16 |
17 | static float minusBy5(float i) {
18 | return i - 5.0f;
19 | }
20 |
21 |
22 | class MyFunction {
23 | public:
24 | std::string concat(std::string& str) const {
25 | return info_ + str;
26 | }
27 |
28 | static int multiply(int i, int j) {
29 | return i * j;
30 | }
31 |
32 | private:
33 | std::string info_ = "MyFunction : ";
34 | };
35 |
36 | #endif //CGRAPH_MYFUNCTION_H
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | CThreadPool 说明文档
10 |
11 |
12 | ## 一. 简介
13 | `CThreadPool` 是一个跨平台的、无任何三方依赖的、head-only的、高性能的C++11(含以上版本)版本的线程池,也是 [CGraph](https://github.com/ChunelFeng/CGraph) 项目中使用的跨平台线程池组件功能的最小集。
14 |
15 | 经过CGraph和关联项目的长期迭代和验证,功能已经趋于稳定,且性能优异。因为咨询相关内容的朋友较多,故做为独立的仓库提供出来,方便大家使用。
16 |
17 | 由于是CGraph项目中的剥离出来的功能类,故在项目中保留了多处 `CGRAPH_*` 的命名方式,仅将 namespace 修改为 `CTP`,预计今后与CGraph相互独立更新。
18 |
19 | 本项目参考了[《C++并发编程实战(第二版)》](https://nj.gitbooks.io/c/content/) 中的部分内容,和github上的一些优秀实现。并在此基础上进行大量的改动、扩展和优化,在功能、性能和易用性上均有较大的提升。
20 |
21 | 在开发过程中,也沉淀了详细的说明文档(见下方 推荐阅读),以便于大家快速了解代码和思路,也请大家不吝指教。
22 |
23 | ## 二. 编译说明
24 | * 本工程支持MacOS、Linux和Windows系统,无任何第三方依赖。推荐使用C++11(默认)或以上版本,不支持以下C++11以下版本
25 |
26 | * 使用`CLion`或使用`Visual Studio 15`(或以上版本)作为IDE的开发者,打开`CMakeLists.txt`文件作为工程,即可编译通过
27 |
28 | * Linux环境开发者,在命令行模式下,输入以下指令,即可编译通过
29 | ```shell
30 | $ git clone https://github.com/ChunelFeng/CThreadPool.git
31 | $ cd CThreadPool
32 | $ cmake . -Bbuild
33 | $ cd build
34 | $ make -j8
35 | ```
36 |
37 | ## 三. 使用Demo
38 | ```cpp
39 | #include "src/CThreadPool.h"
40 |
41 | using namespace CTP;
42 |
43 | float add_by_5(float i) {
44 | return i + 5.0f;
45 | }
46 |
47 | int main() {
48 | UThreadPool tp;
49 | int i = 6, j = 3;
50 | auto r1 = tp.commit([i, j] { return i - j; });
51 | std::future r2 = tp.commit(std::bind(add_by_5, 8.5f));
52 |
53 | std::cout << r1.get() << std::endl;
54 | std::cout << r2.get() << std::endl;
55 | return 0;
56 | }
57 | ```
58 | 更多使用方法,请参考 `tutorial.cpp` 中的例子和文档中的内容。
59 |
60 | ## 四. 推荐阅读
61 | * [纯序员给你介绍图化框架的简单实现——线程池优化(一)](http://www.chunel.cn/archives/cgraph-threadpool-1-introduce)
62 | * [纯序员给你介绍图化框架的简单实现——线程池优化(二)](http://www.chunel.cn/archives/cgraph-threadpool-2-introduce)
63 | * [纯序员给你介绍图化框架的简单实现——线程池优化(三)](http://www.chunel.cn/archives/cgraph-threadpool-3-introduce)
64 | * [纯序员给你介绍图化框架的简单实现——线程池优化(四)](http://www.chunel.cn/archives/cgraph-threadpool-4-introduce)
65 | * [纯序员给你介绍图化框架的简单实现——线程池优化(五)](http://www.chunel.cn/archives/cgraph-threadpool-5-introduce)
66 | * [纯序员给你介绍图化框架的简单实现——线程池优化(六)](http://www.chunel.cn/archives/cgraph-threadpool-6-introduce)
67 |
68 | ## 五. 关联项目
69 | * [CGraph : A simple C++ DAG framework](https://github.com/ChunelFeng/CGraph)
70 |
71 | ------------
72 | #### 附录-1. 版本信息
73 | [2022.10.05 - v1.0.0 - Chunel]
74 | * 提供线程池基本功能
75 | * 提供对应的tutorial信息
76 |
77 | [2022.10.07 - v1.0.1 - Chunel]
78 | * 提供默认开启辅助线程的配置
79 |
80 | [2022.10.11 - v1.1.0 - [MirrorYuChen](https://github.com/MirrorYuChen)]
81 | * 提供针对C++11版本的支持
82 |
83 | [2023.03.07 - v1.2.0 - Chunel]
84 | * 优化windows版本功能
85 |
86 | [2023.11.09 - v1.2.1 - Chunel]
87 | * 更新执行策略,优化整体性能
88 | * 修复辅助线程唤醒延时的问题
89 |
90 | [2025.04.17 - v1.3.0 - Chunel]
91 | * 提供 head-only 版本
92 |
93 | ------------
94 | #### 附录-2. 联系方式
95 | * 微信: ChunelFeng
96 | * 邮箱: chunel@foxmail.com
97 | * 源码: https://github.com/ChunelFeng/CThreadPool
98 | * 论坛: www.chunel.cn
99 |
100 | 
101 |
--------------------------------------------------------------------------------
/cmake/CThreadPool-env-include.cmake:
--------------------------------------------------------------------------------
1 |
2 | # 本cmake文件,供三方引入CGraph引用,用于屏蔽系统和C++版本的区别
3 |
4 | IF(APPLE)
5 | # 非mac平台,暂时不支持自动生成session信息
6 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64 -finline-functions -Wno-deprecated-declarations -Wno-c++17-extensions")
7 | add_definitions(-D_GENERATE_SESSION_)
8 | add_definitions(-D_ENABLE_LIKELY_)
9 | ELSEIF(UNIX)
10 | # linux平台,加入多线程内容
11 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -pthread -Wno-format-overflow")
12 | add_definitions(-D_ENABLE_LIKELY_)
13 | ELSEIF(WIN32)
14 | # windows平台,加入utf-8设置。否则无法通过编译
15 | add_definitions(/utf-8)
16 |
17 | # 禁止两处warning级别提示
18 | add_compile_options(/wd4996)
19 | add_compile_options(/wd4267)
20 | ENDIF()
21 |
--------------------------------------------------------------------------------
/doc/image/CThreadPool Author.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChunelFeng/CThreadPool/7b2d2e572740bf0902614b073537953141fceda2/doc/image/CThreadPool Author.jpg
--------------------------------------------------------------------------------
/src/CBasic/CBasicDefine.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: CBasicDefine.h
5 | @Time: 2021/4/26 8:15 下午
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_CBASICDEFINE_H
10 | #define CGRAPH_CBASICDEFINE_H
11 |
12 | #include
13 |
14 | #define CGRAPH_NAMESPACE_BEGIN \
15 | namespace CTP { \
16 |
17 | #define CGRAPH_NAMESPACE_END \
18 | } /* end of namespace CTP */ \
19 |
20 | CGRAPH_NAMESPACE_BEGIN
21 |
22 | using CCHAR = char;
23 | using CUINT = unsigned int;
24 | using CVOID = void;
25 | using CINT = int;
26 | using CLONG = long;
27 | using CULONG = unsigned long;
28 | using CBOOL = bool;
29 | using CBIGBOOL = int;
30 | using CFLOAT = float;
31 | using CDOUBLE = double;
32 | using CCONSTR = const char*;
33 | using CSIZE = size_t;
34 |
35 | CGRAPH_NAMESPACE_END
36 |
37 | #endif //CGRAPH_CBASICDEFINE_H
38 |
--------------------------------------------------------------------------------
/src/CBasic/CBasicInclude.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: CBasicInclude.h
5 | @Time: 2022/2/1 4:23 下午
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_CBASICINCLUDE_H
10 | #define CGRAPH_CBASICINCLUDE_H
11 |
12 | #include "CObject.h"
13 | #include "CValType.h"
14 | #include "CFuncType.h"
15 | #include "CStatus.h"
16 | #include "CException.h"
17 | #include "CBasicDefine.h"
18 | #include "CStrDefine.h"
19 | #include "CStdEx.h"
20 | #include "CDescInfo.h"
21 | #include "CStruct.h"
22 |
23 | #endif //CGRAPH_CBASICINCLUDE_H
24 |
--------------------------------------------------------------------------------
/src/CBasic/CDescInfo.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: CDescInfo.h
5 | @Time: 2023/2/19 15:56
6 | @Desc: 通用描述信息
7 | ***************************/
8 |
9 | #ifndef CGRAPH_CDESCINFO_H
10 | #define CGRAPH_CDESCINFO_H
11 |
12 | #include
13 |
14 | #include "CBasicDefine.h"
15 |
16 | CGRAPH_NAMESPACE_BEGIN
17 |
18 | class CDescInfo {
19 | public:
20 | /**
21 | * 获取名称信息
22 | * @return
23 | */
24 | const std::string& getName() const {
25 | return name_;
26 | }
27 |
28 | /**
29 | * 获取唯一id信息
30 | * @return
31 | */
32 | const std::string& getSession() const {
33 | return session_;
34 | }
35 |
36 | /**
37 | * 获取描述信息
38 | * @return
39 | */
40 | const std::string& getDescription() const {
41 | return description_;
42 | }
43 |
44 | /**
45 | * 设置名称信息
46 | * @param name
47 | * @return
48 | */
49 | virtual auto setName(const std::string& name)
50 | -> decltype(this) {
51 | name_ = name;
52 | return this;
53 | }
54 |
55 | /**
56 | * 设置描述信息
57 | * @param description
58 | * @return
59 | */
60 | virtual auto setDescription(const std::string& description)
61 | -> decltype(this) {
62 | description_ = description;
63 | return this;
64 | }
65 |
66 | virtual ~CDescInfo() = default;
67 |
68 | protected:
69 | std::string name_; // 名字
70 | std::string session_; // 唯一id信息
71 | std::string description_; // 描述信息
72 | };
73 |
74 | CGRAPH_NAMESPACE_END
75 |
76 | #endif //CGRAPH_CDESCINFO_H
77 |
--------------------------------------------------------------------------------
/src/CBasic/CException.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: CException.h
5 | @Time: 2022/4/15 20:51
6 | @Desc: 异常处理类
7 | ***************************/
8 |
9 | #ifndef CGRAPH_CEXCEPTION_H
10 | #define CGRAPH_CEXCEPTION_H
11 |
12 | #include
13 | #include
14 |
15 | #include "CStrDefine.h"
16 |
17 | CGRAPH_NAMESPACE_BEGIN
18 |
19 | class CEXCEPTION : public std::exception {
20 | public:
21 | explicit CEXCEPTION(const std::string& info,
22 | const std::string& locate = CGRAPH_EMPTY) {
23 | /**
24 | * 这里的设计,和CStatus有一个联动
25 | * 如果不了解具体情况,不建议做任何修改
26 | */
27 | exception_info_ = locate + " | " + info;
28 | }
29 |
30 | /**
31 | * 获取异常信息
32 | * @return
33 | */
34 | const char* what() const noexcept override {
35 | return exception_info_.c_str();
36 | }
37 |
38 | private:
39 | std::string exception_info_; // 异常状态信息
40 | };
41 |
42 | CGRAPH_NAMESPACE_END
43 |
44 | #endif //CGRAPH_CEXCEPTION_H
45 |
--------------------------------------------------------------------------------
/src/CBasic/CFuncType.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: CFuncType.h
5 | @Time: 2022/2/3 1:05 下午
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_CFUNCTYPE_H
10 | #define CGRAPH_CFUNCTYPE_H
11 |
12 | #include
13 |
14 | #include "CStrDefine.h"
15 | #include "CValType.h"
16 |
17 | CGRAPH_NAMESPACE_BEGIN
18 |
19 | using CGRAPH_DEFAULT_FUNCTION = std::function;
20 | using CGRAPH_DEFAULT_CONST_FUNCTION_REF = const std::function&;
21 | using CGRAPH_CSTATUS_FUNCTION = std::function;
22 | using CGRAPH_CSTATUS_CONST_FUNCTION_REF = const std::function&;
23 | using CGRAPH_CALLBACK_FUNCTION = std::function;
24 | using CGRAPH_CALLBACK_CONST_FUNCTION_REF = const std::function&;
25 |
26 |
27 | /**
28 | * 描述函数类型
29 | */
30 | enum class CFunctionType {
31 | INIT = 1, /** 初始化函数 */
32 | RUN = 2, /** 执行函数 */
33 | DESTROY = 3 /** 释放函数 */
34 | };
35 |
36 | /** 开启函数流程 */
37 | #define CGRAPH_FUNCTION_BEGIN \
38 | CStatus status; \
39 |
40 | /** 结束函数流程 */
41 | #define CGRAPH_FUNCTION_END \
42 | return status; \
43 |
44 | /** 无任何功能函数 */
45 | #define CGRAPH_EMPTY_FUNCTION \
46 | return CStatus(); \
47 |
48 |
49 | /** 获取当前代码所在的位置信息 */
50 | #define CGRAPH_GET_LOCATE \
51 | (std::string(__FILE__) + " | " + std::string(__FUNCTION__) \
52 | + " | line = [" + ::std::to_string( __LINE__) + "]")
53 |
54 |
55 | /** 生成一个包含异常位置的 CStatus
56 | * 这里这样实现,是为了符合 CStatus 类似写法
57 | * */
58 | #define CErrStatus(info) \
59 | CStatus(info, CGRAPH_GET_LOCATE) \
60 |
61 | /** 返回异常信息和状态 */
62 | #define CGRAPH_RETURN_ERROR_STATUS(info) \
63 | return CErrStatus(info); \
64 |
65 | /** 根据条件判断是否返回错误状态 */
66 | #define CGRAPH_RETURN_ERROR_STATUS_BY_CONDITION(cond, info) \
67 | if (unlikely(cond)) { CGRAPH_RETURN_ERROR_STATUS(info); } \
68 |
69 | /** 不支持当前功能 */
70 | #define CGRAPH_NO_SUPPORT \
71 | return CErrStatus(CGRAPH_FUNCTION_NO_SUPPORT); \
72 |
73 | /** 定义为不能赋值和拷贝的对象类型 */
74 | #define CGRAPH_NO_ALLOWED_COPY(CType) \
75 | CType(const CType &) = delete; \
76 | const CType &operator=(const CType &) = delete; \
77 |
78 | /** 抛出异常 */
79 | #define CGRAPH_THROW_EXCEPTION(info) \
80 | throw CException(info, CGRAPH_GET_LOCATE); \
81 |
82 | /** 在异常状态的情况下,抛出异常 */
83 | #define CGRAPH_THROW_EXCEPTION_BY_STATUS(status) \
84 | if (unlikely((status).isErr())) { \
85 | CGRAPH_THROW_EXCEPTION((status).getInfo()); \
86 | } \
87 |
88 | /** 根据条件判断是否抛出异常 */
89 | #define CGRAPH_THROW_EXCEPTION_BY_CONDITION(cond, info) \
90 | if (unlikely(cond)) { CGRAPH_THROW_EXCEPTION(info); } \
91 |
92 |
93 | CGRAPH_NAMESPACE_END
94 |
95 | #endif //CGRAPH_CFUNCTYPE_H
96 |
--------------------------------------------------------------------------------
/src/CBasic/CObject.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: CObject.h
5 | @Time: 2021/4/26 8:12 下午
6 | @Desc: 所有类型的父节点,其中run()方法必须实现
7 | ***************************/
8 |
9 | #ifndef CGRAPH_COBJECT_H
10 | #define CGRAPH_COBJECT_H
11 |
12 | #include "CBasicDefine.h"
13 | #include "CValType.h"
14 | #include "CFuncType.h"
15 |
16 | CGRAPH_NAMESPACE_BEGIN
17 |
18 | class CObject {
19 | public:
20 | /**
21 | * 默认构造函数
22 | */
23 | explicit CObject() = default;
24 |
25 | /**
26 | * 初始化函数
27 | */
28 | virtual CStatus init() {
29 | CGRAPH_EMPTY_FUNCTION
30 | }
31 |
32 | /**
33 | * 流程处理函数
34 | */
35 | virtual CStatus run() = 0;
36 |
37 | /**
38 | * 释放函数
39 | */
40 | virtual CStatus destroy() {
41 | CGRAPH_EMPTY_FUNCTION
42 | }
43 |
44 | /**
45 | * 默认析构函数
46 | */
47 | virtual ~CObject() = default;
48 | };
49 |
50 | CGRAPH_NAMESPACE_END
51 |
52 | #endif //CGRAPH_COBJECT_H
53 |
--------------------------------------------------------------------------------
/src/CBasic/CStatus.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: CStatus.h
5 | @Time: 2021/12/17 10:32 下午
6 | @Desc: 命名为 CSTATUS,直接对外提供的是 CStatus 类
7 | ***************************/
8 |
9 | #ifndef CGRAPH_CSTATUS_H
10 | #define CGRAPH_CSTATUS_H
11 |
12 | #include
13 |
14 | #include "CBasicDefine.h"
15 | #include "CStrDefine.h"
16 |
17 | CGRAPH_NAMESPACE_BEGIN
18 |
19 | /**
20 | * 说明:
21 | * 返回值为0,表示正常逻辑
22 | * 返回值为负整数,表示error逻辑,程序终止执行
23 | * 自定义返回值,请务必遵守以上约定
24 | */
25 | static const int STATUS_OK = 0; /** 正常流程返回值 */
26 | static const int STATUS_ERR = -1; /** 异常流程返回值 */
27 | static const int STATUS_CRASH = -996; /** 异常流程返回值 */
28 | static const char* STATUS_ERROR_INFO_CONNECTOR = " && "; /** 多异常信息连接符号 */
29 |
30 | class CSTATUS {
31 | public:
32 | explicit CSTATUS() = default;
33 |
34 | explicit CSTATUS(const std::string &errorInfo,
35 | const std::string &locateInfo = CGRAPH_EMPTY) {
36 | this->error_code_ = STATUS_ERR; // 默认的error code信息
37 | this->error_info_ = errorInfo;
38 | this->error_locate_ = locateInfo;
39 | }
40 |
41 | explicit CSTATUS(int errorCode, const std::string &errorInfo,
42 | const std::string &locateInfo = CGRAPH_EMPTY) {
43 | this->error_code_ = errorCode;
44 | this->error_info_ = errorInfo;
45 | this->error_locate_ = locateInfo;
46 | }
47 |
48 | CSTATUS(const CSTATUS &status) {
49 | if (status.isOK()) {
50 | return;
51 | }
52 |
53 | this->error_code_ = status.error_code_;
54 | this->error_info_ = status.error_info_;
55 | this->error_locate_ = status.error_locate_;
56 | }
57 |
58 | CSTATUS(const CSTATUS &&status) noexcept {
59 | if (status.isOK()) {
60 | return;
61 | }
62 |
63 | this->error_code_ = status.error_code_;
64 | this->error_info_ = status.error_info_;
65 | this->error_locate_ = status.error_locate_;
66 | }
67 |
68 | CSTATUS& operator=(const CSTATUS& status) {
69 | if (!status.isOK()) {
70 | // 如果status是正常的话,则所有数据保持不变
71 | this->error_code_ = status.error_code_;
72 | this->error_info_ = status.error_info_;
73 | this->error_locate_ = status.error_locate_;
74 | }
75 | return (*this);
76 | }
77 |
78 | CSTATUS& operator+=(const CSTATUS& cur) {
79 | /**
80 | * 如果当前状态已经异常,则不做改动
81 | * 如果当前状态正常,并且传入的状态是异常的话,则返回异常
82 | */
83 | if (!this->isErr() && cur.isErr()) {
84 | this->error_code_ = cur.error_code_;
85 | this->error_info_ = cur.error_info_;
86 | this->error_locate_ = cur.error_locate_;
87 | }
88 |
89 | return (*this);
90 | }
91 |
92 | /**
93 | * 获取异常值信息
94 | * @return
95 | */
96 | int getCode() const {
97 | return this->error_code_;
98 | }
99 |
100 | /**
101 | * 获取异常信息
102 | * @return
103 | */
104 | const std::string& getInfo() const {
105 | return this->error_info_;
106 | }
107 |
108 | /**
109 | * 获取报错位置
110 | * @return
111 | */
112 | const std::string& getLocate() const {
113 | return this->error_locate_;
114 | }
115 |
116 | /**
117 | * 判断当前状态是否可行
118 | * @return
119 | */
120 | bool isOK() const {
121 | return STATUS_OK == error_code_;
122 | }
123 |
124 | /**
125 | * 判断当前状态是否可行
126 | * @return
127 | */
128 | bool isErr() const {
129 | return error_code_ < STATUS_OK; // 约定异常信息,均为负值
130 | }
131 |
132 | /**
133 | * 判断当前状态是否是崩溃了
134 | * @return
135 | */
136 | bool isCrash() const {
137 | return STATUS_CRASH == error_code_;
138 | }
139 |
140 | private:
141 | int error_code_ = STATUS_OK; // 错误码信息
142 | std::string error_info_; // 错误信息描述
143 | std::string error_locate_; // 错误发生的具体位置,形如:file|function|line
144 | };
145 |
146 | CGRAPH_NAMESPACE_END
147 |
148 | #endif //CGRAPH_CSTATUS_H
149 |
--------------------------------------------------------------------------------
/src/CBasic/CStdEx.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: CStdEx.h
5 | @Time: 2023/1/31 23:15
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_CSTDEX_H
10 | #define CGRAPH_CSTDEX_H
11 |
12 | #include
13 | #include
14 |
15 | CGRAPH_NAMESPACE_BEGIN
16 |
17 | // 兼容 std::enable_if_t 的语法
18 | template
19 | using c_enable_if_t = typename std::enable_if::type;
20 |
21 | // 兼容 std::make_unique 的语法
22 | template
23 | typename std::unique_ptr c_make_unique(Args&&... args) {
24 | return std::unique_ptr(new T(std::forward(args)...));
25 | }
26 |
27 | CGRAPH_NAMESPACE_END
28 |
29 | #endif //CGRAPH_CSTDEX_H
30 |
--------------------------------------------------------------------------------
/src/CBasic/CStrDefine.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: CInfoDefine.h
5 | @Time: 2022/4/16 14:01
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_CSTRDEFINE_H
10 | #define CGRAPH_CSTRDEFINE_H
11 |
12 | #include
13 |
14 | #include "CBasicDefine.h"
15 |
16 | CGRAPH_NAMESPACE_BEGIN
17 |
18 | static const std::string& CGRAPH_EMPTY = "";
19 | static const std::string& CGRAPH_DEFAULT = "default";
20 | static const std::string& CGRAPH_UNKNOWN = "unknown";
21 | static const std::string& CGRAPH_BASIC_EXCEPTION = "CGraph default exception";
22 | static const std::string& CGRAPH_FUNCTION_NO_SUPPORT = "CGraph function no support";
23 | static const std::string& CGRAPH_INPUT_IS_NULL = "input is nullptr";
24 |
25 | CGRAPH_NAMESPACE_END
26 |
27 | #endif //CGRAPH_CSTRDEFINE_H
28 |
--------------------------------------------------------------------------------
/src/CBasic/CStruct.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: CStruct.h
5 | @Time: 2023/7/16 11:36
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_CSTRUCT_H
10 | #define CGRAPH_CSTRUCT_H
11 |
12 | #include "CBasicDefine.h"
13 |
14 | CGRAPH_NAMESPACE_BEGIN
15 |
16 | /**
17 | * 所有框架内部结构体定义的基类
18 | * 仅针对类似 bean 数据类型的定义
19 | */
20 | class CStruct {
21 | };
22 |
23 | CGRAPH_NAMESPACE_END
24 |
25 | #endif //CGRAPH_CSTRUCT_H
26 |
--------------------------------------------------------------------------------
/src/CBasic/CValType.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: CValTypes.h
5 | @Time: 2022/2/3 12:58 下午
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_CVALTYPE_H
10 | #define CGRAPH_CVALTYPE_H
11 |
12 | #include "CBasicDefine.h"
13 | #include "CStatus.h"
14 | #include "CException.h"
15 |
16 | using CChar = CTP::CCHAR;
17 | using CUint = CTP::CUINT;
18 | using CSize = CTP::CSIZE;
19 | using CVoid = CTP::CVOID;
20 | using CVoidPtr = CTP::CVOID *;
21 | using CInt = CTP::CINT;
22 | using CLong = CTP::CLONG;
23 | using CULong = CTP::CULONG;
24 | using CBool = CTP::CBOOL;
25 | using CIndex = CTP::CINT; // 表示标识信息,可以为负数
26 | using CFloat = CTP::CFLOAT;
27 | using CDouble = CTP::CDOUBLE;
28 | using CConStr = CTP::CCONSTR; // 表示 const char*
29 | using CBigBool = CTP::CBIGBOOL;
30 |
31 | using CLevel = CTP::CINT;
32 | using CSec = CTP::CLONG; // 表示秒信息, for second
33 | using CMSec = CTP::CLONG; // 表示毫秒信息, for millisecond
34 | using CFMSec = CTP::CDOUBLE; // 表示毫秒信息,包含小数点信息
35 |
36 | using CStatus = CTP::CSTATUS;
37 | using CException = CTP::CEXCEPTION;
38 |
39 | #endif //CGRAPH_CVALTYPE_H
40 |
--------------------------------------------------------------------------------
/src/CThreadPool.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: CThreadPool.h
5 | @Time: 2022/10/5 20:08
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CTHREADPOOL_CTHREADPOOL_H
10 | #define CTHREADPOOL_CTHREADPOOL_H
11 |
12 | #include "CBasic/CBasicInclude.h"
13 | #include "UtilsCtrl/UtilsInclude.h"
14 |
15 | #endif //CTHREADPOOL_CTHREADPOOL_H
16 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Lock/ULockInclude.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: ULockInclude.h
5 | @Time: 2023/2/21 22:19
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_ULOCKINCLUDE_H
10 | #define CGRAPH_ULOCKINCLUDE_H
11 |
12 | #include "USpinLock.h"
13 |
14 | #endif //CGRAPH_ULOCKINCLUDE_H
15 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Lock/USpinLock.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: USpinLock.h
5 | @Time: 2023/2/21 22:17
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_USPINLOCK_H
10 | #define CGRAPH_USPINLOCK_H
11 |
12 | #include
13 |
14 | #include "../UThreadObject.h"
15 |
16 | CGRAPH_NAMESPACE_BEGIN
17 |
18 | class USpinLock : public UThreadObject {
19 | public:
20 | /**
21 | * 加锁
22 | */
23 | CVoid lock() {
24 | // memory_order_acquire 后面访存指令勿重排至此条指令之前
25 | while (flag_.test_and_set(std::memory_order_acquire)) {
26 | }
27 | }
28 |
29 | /**
30 | * 解锁
31 | */
32 | CVoid unlock() {
33 | // memory_order_release 前面访存指令勿重排到此条指令之后
34 | flag_.clear(std::memory_order_release);
35 | }
36 |
37 | /**
38 | * 尝试加锁。若未加锁,会上锁
39 | * @return
40 | */
41 | CBool tryLock() {
42 | return !flag_.test_and_set();
43 | }
44 |
45 | private:
46 | std::atomic_flag flag_ = ATOMIC_FLAG_INIT; // 标志位
47 | };
48 |
49 | CGRAPH_NAMESPACE_END
50 |
51 | #endif //CGRAPH_USPINLOCK_H
52 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Queue/UAtomicPriorityQueue.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: UAtomicPriorityQueue.h
5 | @Time: 2022/10/1 21:40
6 | @Desc: 线程安全的优先队列。因为 priority_queue和queue的弹出方式不一致,故暂时不做合并
7 | ***************************/
8 |
9 | #ifndef CGRAPH_UATOMICPRIORITYQUEUE_H
10 | #define CGRAPH_UATOMICPRIORITYQUEUE_H
11 |
12 | #include
13 |
14 | #include "UQueueObject.h"
15 |
16 | CGRAPH_NAMESPACE_BEGIN
17 |
18 | template
19 | class UAtomicPriorityQueue : public UQueueObject {
20 | public:
21 | UAtomicPriorityQueue() = default;
22 |
23 | /**
24 | * 尝试弹出
25 | * @param value
26 | * @return
27 | */
28 | CBool tryPop(T& value) {
29 | CBool result = false;
30 | if (mutex_.try_lock()) {
31 | if (!priority_queue_.empty()) {
32 | value = std::move(*priority_queue_.top());
33 | priority_queue_.pop();
34 | result = true;
35 | }
36 | mutex_.unlock();
37 | }
38 |
39 | return result;
40 | }
41 |
42 |
43 | /**
44 | * 尝试弹出多个任务
45 | * @param values
46 | * @param maxPoolBatchSize
47 | * @return
48 | */
49 | CBool tryPop(std::vector& values, int maxPoolBatchSize) {
50 | CBool result = false;
51 | if (mutex_.try_lock()) {
52 | while (!priority_queue_.empty() && maxPoolBatchSize-- > 0) {
53 | values.emplace_back(std::move(*priority_queue_.top()));
54 | priority_queue_.pop();
55 | result = true;
56 | }
57 | mutex_.unlock();
58 | }
59 |
60 | return result;
61 | }
62 |
63 |
64 | /**
65 | * 传入数据
66 | * @param value
67 | * @param priority 任务优先级,数字排序
68 | * @return
69 | */
70 | CVoid push(T&& value, int priority) {
71 | std::unique_ptr task(c_make_unique(std::move(value), priority));
72 | CGRAPH_LOCK_GUARD lk(mutex_);
73 | priority_queue_.push(std::move(task));
74 | }
75 |
76 |
77 | /**
78 | * 判定队列是否为空
79 | * @return
80 | */
81 | CBool empty() {
82 | CGRAPH_LOCK_GUARD lk(mutex_);
83 | return priority_queue_.empty();
84 | }
85 |
86 | CGRAPH_NO_ALLOWED_COPY(UAtomicPriorityQueue)
87 |
88 | private:
89 | std::priority_queue > priority_queue_; // 优先队列信息,根据重要级别决定先后执行顺序
90 | };
91 |
92 | CGRAPH_NAMESPACE_END
93 |
94 | #endif //CGRAPH_UATOMICPRIORITYQUEUE_H
95 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Queue/UAtomicQueue.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: UAtomicQueue.h
5 | @Time: 2021/7/2 11:28 下午
6 | @Desc: 设计了一个安全队列
7 | ***************************/
8 |
9 | #ifndef CGRAPH_UATOMICQUEUE_H
10 | #define CGRAPH_UATOMICQUEUE_H
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | #include "../UThreadPoolDefine.h"
18 | #include "UQueueObject.h"
19 |
20 | CGRAPH_NAMESPACE_BEGIN
21 |
22 | template
23 | class UAtomicQueue : public UQueueObject {
24 | public:
25 | UAtomicQueue() = default;
26 |
27 | /**
28 | * 等待弹出
29 | * @param value
30 | */
31 | CVoid waitPop(T& value) {
32 | CGRAPH_UNIQUE_LOCK lk(mutex_);
33 | cv_.wait(lk, [this] { return !queue_.empty(); });
34 | value = std::move(*queue_.front());
35 | queue_.pop();
36 | }
37 |
38 |
39 | /**
40 | * 尝试弹出
41 | * @param value
42 | * @return
43 | */
44 | CBool tryPop(T& value) {
45 | CBool result = false;
46 | if (!queue_.empty() && mutex_.try_lock()) {
47 | if (!queue_.empty()) {
48 | value = std::move(*queue_.front());
49 | queue_.pop();
50 | result = true;
51 | }
52 | mutex_.unlock();
53 | }
54 |
55 | return result;
56 | }
57 |
58 |
59 | /**
60 | * 尝试弹出多个任务
61 | * @param values
62 | * @param maxPoolBatchSize
63 | * @return
64 | */
65 | CBool tryPop(std::vector& values, int maxPoolBatchSize) {
66 | CBool result = false;
67 | if (!queue_.empty() && mutex_.try_lock()) {
68 | while (!queue_.empty() && maxPoolBatchSize-- > 0) {
69 | values.emplace_back(std::move(*queue_.front()));
70 | queue_.pop();
71 | result = true;
72 | }
73 | mutex_.unlock();
74 | }
75 |
76 | return result;
77 | }
78 |
79 |
80 | /**
81 | * 阻塞式等待弹出
82 | * @return
83 | */
84 | std::unique_ptr popWithTimeout(CMSec ms) {
85 | CGRAPH_UNIQUE_LOCK lk(mutex_);
86 | if (!cv_.wait_for(lk, std::chrono::milliseconds(ms),
87 | [this] { return (!queue_.empty()) || (!ready_flag_); })) {
88 | return nullptr;
89 | }
90 | if (queue_.empty() || !ready_flag_) {
91 | return nullptr;
92 | }
93 |
94 | std::unique_ptr result = std::move(queue_.front());
95 | queue_.pop(); // 如果等成功了,则弹出一个信息
96 | return result;
97 | }
98 |
99 |
100 | /**
101 | * 非阻塞式等待弹出
102 | * @return
103 | */
104 | std::unique_ptr tryPop() {
105 | CGRAPH_LOCK_GUARD lk(mutex_);
106 | if (queue_.empty()) { return std::unique_ptr(); }
107 | std::unique_ptr ptr = std::move(queue_.front());
108 | queue_.pop();
109 | return ptr;
110 | }
111 |
112 |
113 | /**
114 | * 传入数据
115 | * @param value
116 | */
117 | CVoid push(T&& value) {
118 | std::unique_ptr::type> \
119 | task(c_make_unique::type>(std::forward(value)));
120 | while (true) {
121 | if (mutex_.try_lock()) {
122 | queue_.push(std::move(task));
123 | mutex_.unlock();
124 | break;
125 | } else {
126 | std::this_thread::yield();
127 | }
128 | }
129 | cv_.notify_one();
130 | }
131 |
132 |
133 | /**
134 | * 判定队列是否为空
135 | * @return
136 | */
137 | CBool empty() {
138 | CGRAPH_LOCK_GUARD lk(mutex_);
139 | return queue_.empty();
140 | }
141 |
142 | /**
143 | * 功能是通知所有的辅助线程停止工作
144 | * @return
145 | */
146 | CVoid reset() {
147 | ready_flag_ = false;
148 | cv_.notify_all();
149 | }
150 |
151 | /**
152 | * 初始化状态
153 | * @return
154 | */
155 | CVoid setup() {
156 | ready_flag_ = true;
157 | queue_ = {};
158 | }
159 |
160 | CGRAPH_NO_ALLOWED_COPY(UAtomicQueue)
161 |
162 | private:
163 | std::queue> queue_; // 任务队列
164 | CBool ready_flag_ { true }; // 执行标记,主要用于快速释放 destroy 逻辑中,多个辅助线程等待的状态
165 | };
166 |
167 | CGRAPH_NAMESPACE_END
168 |
169 | #endif //CGRAPH_UATOMICQUEUE_H
170 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Queue/UAtomicRingBufferQueue.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: UAtomicRingBufferQueue.h
5 | @Time: 2022/10/22 22:32
6 | @Desc: 本 queue 仅支持单入单出模式
7 | ***************************/
8 |
9 | #ifndef CGRAPH_UATOMICRINGBUFFERQUEUE_H
10 | #define CGRAPH_UATOMICRINGBUFFERQUEUE_H
11 |
12 | #include
13 | #include
14 | #include
15 |
16 | #include "UQueueObject.h"
17 |
18 | CGRAPH_NAMESPACE_BEGIN
19 |
20 | template
21 | class UAtomicRingBufferQueue : public UQueueObject {
22 | public:
23 | explicit UAtomicRingBufferQueue() {
24 | head_ = 0;
25 | tail_ = 0;
26 | capacity_ = capacity;
27 | ring_buffer_queue_.resize(capacity_);
28 | }
29 |
30 | ~UAtomicRingBufferQueue() override {
31 | clear();
32 | }
33 |
34 | /**
35 | * 设置容量信息
36 | * @param size
37 | * @return
38 | * @notice 谨慎使用,push信息之后,不推荐使用
39 | */
40 | UAtomicRingBufferQueue* setCapacity(CUint size) {
41 | capacity_ = size;
42 | ring_buffer_queue_.resize(capacity_);
43 | return this;
44 | }
45 |
46 | /**
47 | * 获取容量信息
48 | * @return
49 | */
50 | CUint getCapacity() const {
51 | return capacity_;
52 | }
53 |
54 | /**
55 | * 写入信息
56 | * @tparam TImpl
57 | * @param value
58 | * @param strategy
59 | * @return
60 | */
61 | template
62 | CVoid push(const TImpl& value, URingBufferPushStrategy strategy) {
63 | {
64 | CGRAPH_UNIQUE_LOCK lk(mutex_);
65 | if (isFull()) {
66 | switch (strategy) {
67 | case URingBufferPushStrategy::WAIT:
68 | push_cv_.wait(lk, [this] { return !isFull(); });
69 | break;
70 | case URingBufferPushStrategy::REPLACE:
71 | head_ = (head_ + 1) % capacity_;
72 | break;
73 | case URingBufferPushStrategy::DROP:
74 | return; // 直接返回,不写入即可
75 | }
76 | }
77 |
78 | ring_buffer_queue_[tail_] = std::move(c_make_unique(value));
79 | tail_ = (tail_ + 1) % capacity_;
80 | }
81 | pop_cv_.notify_one();
82 | }
83 |
84 | /**
85 | * 写入智能指针类型的信息
86 | * @tparam TImpl
87 | * @param value
88 | * @param strategy
89 | * @return
90 | */
91 | template
92 | CVoid push(std::unique_ptr& value, URingBufferPushStrategy strategy) {
93 | {
94 | CGRAPH_UNIQUE_LOCK lk(mutex_);
95 | if (isFull()) {
96 | switch (strategy) {
97 | case URingBufferPushStrategy::WAIT:
98 | push_cv_.wait(lk, [this] { return !isFull(); });
99 | break;
100 | case URingBufferPushStrategy::REPLACE:
101 | head_ = (head_ + 1) % capacity_;
102 | break;
103 | case URingBufferPushStrategy::DROP:
104 | return; // 直接返回,不写入即可
105 | }
106 | }
107 |
108 | ring_buffer_queue_[tail_] = std::move(value);
109 | tail_ = (tail_ + 1) % capacity_;
110 | }
111 | pop_cv_.notify_one();
112 | }
113 |
114 | /**
115 | * 等待弹出信息
116 | * @param value
117 | * @param timeout
118 | * @return
119 | */
120 | template
121 | CStatus waitPopWithTimeout(TImpl& value, CMSec timeout) {
122 | CGRAPH_FUNCTION_BEGIN
123 | {
124 | CGRAPH_UNIQUE_LOCK lk(mutex_);
125 | if (isEmpty()
126 | && !pop_cv_.wait_for(lk, std::chrono::milliseconds(timeout),
127 | [this] { return !isEmpty(); })) {
128 | // 如果timeout的时间内,等不到消息,则返回错误信息
129 | CGRAPH_RETURN_ERROR_STATUS("receive message timeout.")
130 | }
131 |
132 | value = *ring_buffer_queue_[head_]; // 这里直接进行值copy
133 | head_ = (head_ + 1) % capacity_;
134 | }
135 | push_cv_.notify_one();
136 | CGRAPH_FUNCTION_END
137 | }
138 |
139 | /**
140 | * 等待弹出信息。ps:当入参为智能指针的情况
141 | * @tparam TImpl
142 | * @param value
143 | * @param timeout
144 | * @return
145 | */
146 | template
147 | CStatus waitPopWithTimeout(std::unique_ptr& value, CMSec timeout) {
148 | CGRAPH_FUNCTION_BEGIN
149 | {
150 | CGRAPH_UNIQUE_LOCK lk(mutex_);
151 | if (isEmpty()
152 | && !pop_cv_.wait_for(lk, std::chrono::milliseconds(timeout),
153 | [this] { return !isEmpty(); })) {
154 | // 如果timeout的时间内,等不到消息,则返回错误信息
155 | CGRAPH_RETURN_ERROR_STATUS("receive message timeout.")
156 | }
157 |
158 | /**
159 | * 当传入的内容,是智能指针的时候,
160 | * 这里就直接通过 move转移过去好了,跟直接传值的方式,保持区别
161 | */
162 | value = std::move(ring_buffer_queue_[head_]);
163 | head_ = (head_ + 1) % capacity_;
164 | }
165 | push_cv_.notify_one();
166 | CGRAPH_FUNCTION_END
167 | }
168 |
169 | /**
170 | * 清空所有的数据
171 | * @return
172 | */
173 | CStatus clear() {
174 | CGRAPH_FUNCTION_BEGIN
175 | ring_buffer_queue_.resize(0);
176 | head_ = 0;
177 | tail_ = 0;
178 | CGRAPH_FUNCTION_END
179 | }
180 |
181 | protected:
182 | /**
183 | * 当前队列是否为满
184 | * @return
185 | */
186 | CBool isFull() {
187 | // 空出来一个位置,这个时候不让 tail写入
188 | return head_ == (tail_ + 1) % capacity_;
189 | }
190 |
191 | /**
192 | * 当前队列是否为空
193 | * @return
194 | */
195 | CBool isEmpty() {
196 | return head_ == tail_;
197 | }
198 |
199 | CGRAPH_NO_ALLOWED_COPY(UAtomicRingBufferQueue)
200 |
201 | private:
202 | CUint head_; // 头结点位置
203 | CUint tail_; // 尾结点位置
204 | CUint capacity_; // 环形缓冲的容量大小
205 |
206 | std::condition_variable push_cv_; // 写入的条件变量。为了保持语义完整,也考虑今后多入多出的可能性,不使用 父类中的 cv_了
207 | std::condition_variable pop_cv_; // 读取的条件变量
208 |
209 | std::vector > ring_buffer_queue_; // 环形缓冲区
210 | };
211 |
212 | CGRAPH_NAMESPACE_END
213 |
214 | #endif //CGRAPH_UATOMICRINGBUFFERQUEUE_H
215 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Queue/ULockFreeRingBufferQueue.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: ULockFreeRingBufferQueue.h
5 | @Time: 2023/10/7 21:35
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_ULOCKFREERINGBUFFERQUEUE_H
10 | #define CGRAPH_ULOCKFREERINGBUFFERQUEUE_H
11 |
12 | #include
13 | #include
14 |
15 | #include "UQueueObject.h"
16 |
17 | CGRAPH_NAMESPACE_BEGIN
18 |
19 | template
20 | class ULockFreeRingBufferQueue : public UQueueObject {
21 | public:
22 | explicit ULockFreeRingBufferQueue() {
23 | head_ = 0;
24 | tail_ = 0;
25 | ring_buffer_.resize(CAPACITY);
26 | }
27 |
28 | ~ULockFreeRingBufferQueue() override {
29 | ring_buffer_.clear();
30 | }
31 |
32 | /**
33 | * 写入一个任务
34 | * @param value
35 | */
36 | CVoid push(T&& value) {
37 | int curTail = tail_.load(std::memory_order_relaxed);
38 | int nextTail = (curTail + 1) % CAPACITY;
39 |
40 | while (nextTail == head_.load(std::memory_order_acquire)) {
41 | // 队列已满,等待其他线程出队
42 | std::this_thread::yield();
43 | }
44 |
45 | ring_buffer_[curTail] = std::move(value);
46 | tail_.store(nextTail, std::memory_order_release);
47 | }
48 |
49 | /**
50 | * 尝试弹出一个任务
51 | * @param value
52 | * @return
53 | */
54 | CBool tryPop(T& value) {
55 | int curHead = head_.load(std::memory_order_relaxed);
56 | if (curHead == tail_.load(std::memory_order_acquire)) {
57 | // 队列已空,直接返回false
58 | return false;
59 | }
60 |
61 | value = std::move(ring_buffer_[curHead]);
62 |
63 | int nextHead = (curHead + 1) % CAPACITY;
64 | head_.store(nextHead, std::memory_order_release);
65 | return true;
66 | }
67 |
68 |
69 | private:
70 | std::atomic head_; // 开始元素(较早写入的)的位置
71 | std::atomic tail_; // 尾部的位置
72 | std::vector > ring_buffer_; // 环形队列
73 | };
74 |
75 | CGRAPH_NAMESPACE_END
76 |
77 | #endif //CGRAPH_ULOCKFREERINGBUFFERQUEUE_H
78 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Queue/UQueueDefine.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: UQueueDefine.h
5 | @Time: 2023/9/15 21:31
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_UQUEUEDEFINE_H
10 | #define CGRAPH_UQUEUEDEFINE_H
11 |
12 | CGRAPH_NAMESPACE_BEGIN
13 |
14 | /** 当环形队列满的时候,写入信息时候的策略 */
15 | enum class URingBufferPushStrategy {
16 | WAIT = 1, // 等待有数据被消费后,再写入
17 | REPLACE = 2, // 替换未被消费的最早进入的内容
18 | DROP = 3, // 丢弃当前信息
19 | };
20 |
21 | CGRAPH_NAMESPACE_END
22 |
23 | #endif //CGRAPH_UQUEUEDEFINE_H
24 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Queue/UQueueInclude.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: UQueueInclude.h
5 | @Time: 2022/1/12 11:09 下午
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_UQUEUEINCLUDE_H
10 | #define CGRAPH_UQUEUEINCLUDE_H
11 |
12 | #include "UAtomicQueue.h"
13 | #include "UWorkStealingQueue.h"
14 | #include "UAtomicPriorityQueue.h"
15 | #include "UAtomicRingBufferQueue.h"
16 | #include "ULockFreeRingBufferQueue.h"
17 |
18 | #endif //CGRAPH_UQUEUEINCLUDE_H
19 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Queue/UQueueObject.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: UQueueObject.h
5 | @Time: 2022/10/1 20:31
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_UQUEUEOBJECT_H
10 | #define CGRAPH_UQUEUEOBJECT_H
11 |
12 | #include
13 |
14 | #include "../UThreadObject.h"
15 | #include "UQueueDefine.h"
16 |
17 | CGRAPH_NAMESPACE_BEGIN
18 |
19 | class UQueueObject : public UThreadObject {
20 | protected:
21 | std::mutex mutex_;
22 | std::condition_variable cv_;
23 | };
24 |
25 | CGRAPH_NAMESPACE_END
26 |
27 | #endif //CGRAPH_UQUEUEOBJECT_H
28 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Queue/UWorkStealingQueue.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: UWorkStealingQueue.h
5 | @Time: 2021/7/2 11:29 下午
6 | @Desc: 实现了一个包含盗取功能的安全队列
7 | ***************************/
8 |
9 |
10 | #ifndef CGRAPH_UWORKSTEALINGQUEUE_H
11 | #define CGRAPH_UWORKSTEALINGQUEUE_H
12 |
13 | #include
14 |
15 | #include "UQueueObject.h"
16 |
17 | CGRAPH_NAMESPACE_BEGIN
18 |
19 | template
20 | class UWorkStealingQueue : public UQueueObject {
21 | public:
22 | /**
23 | * 向队列中写入信息
24 | * @param task
25 | */
26 | CVoid push(T&& task) {
27 | while (true) {
28 | if (lock_.try_lock()) {
29 | deque_.emplace_front(std::forward(task));
30 | lock_.unlock();
31 | break;
32 | } else {
33 | std::this_thread::yield();
34 | }
35 | }
36 | }
37 |
38 |
39 | /**
40 | * 尝试往队列里写入信息
41 | * @param task
42 | * @return
43 | */
44 | CBool tryPush(T&& task) {
45 | CBool result = false;
46 | if (lock_.try_lock()) {
47 | deque_.emplace_back(std::forward(task));
48 | lock_.unlock();
49 | result = true;
50 | }
51 | return result;
52 | }
53 |
54 |
55 | /**
56 | * 向队列中写入信息
57 | * @param task
58 | */
59 | CVoid push(std::vector& tasks) {
60 | while (true) {
61 | if (lock_.try_lock()) {
62 | for (const auto& task : tasks) {
63 | deque_.emplace_front(std::forward(task));
64 | }
65 | lock_.unlock();
66 | break;
67 | } else {
68 | std::this_thread::yield();
69 | }
70 | }
71 | }
72 |
73 |
74 | /**
75 | * 尝试批量写入内容
76 | * @param tasks
77 | * @return
78 | */
79 | CBool tryPush(std::vector& tasks) {
80 | CBool result = false;
81 | if (lock_.try_lock()) {
82 | for (const auto& task : tasks) {
83 | deque_.emplace_back(std::forward(task));
84 | }
85 | lock_.unlock();
86 | result = true;
87 | }
88 | return result;
89 | }
90 |
91 |
92 | /**
93 | * 弹出节点,从头部进行
94 | * @param task
95 | * @return
96 | */
97 | CBool tryPop(T& task) {
98 | // 这里不使用raii锁,主要是考虑到多线程的情况下,可能会重复进入
99 | bool result = false;
100 | if (!deque_.empty() && lock_.try_lock()) {
101 | if (!deque_.empty()) {
102 | task = std::forward(deque_.front()); // 从前方弹出
103 | deque_.pop_front();
104 | result = true;
105 | }
106 | lock_.unlock();
107 | }
108 |
109 | return result;
110 | }
111 |
112 |
113 | /**
114 | * 从头部开始批量获取可执行任务信息
115 | * @param taskArr
116 | * @param maxLocalBatchSize
117 | * @return
118 | */
119 | CBool tryPop(std::vector& taskArr, int maxLocalBatchSize) {
120 | bool result = false;
121 | if (!deque_.empty() && lock_.try_lock()) {
122 | while (!deque_.empty() && maxLocalBatchSize--) {
123 | taskArr.emplace_back(std::forward(deque_.front()));
124 | deque_.pop_front();
125 | result = true;
126 | }
127 | lock_.unlock();
128 | }
129 |
130 | return result;
131 | }
132 |
133 |
134 | /**
135 | * 窃取节点,从尾部进行
136 | * @param task
137 | * @return
138 | */
139 | CBool trySteal(T& task) {
140 | bool result = false;
141 | if (!deque_.empty() && lock_.try_lock()) {
142 | if (!deque_.empty()) {
143 | task = std::forward(deque_.back()); // 从后方窃取
144 | deque_.pop_back();
145 | result = true;
146 | }
147 | lock_.unlock();
148 | }
149 |
150 | return result;
151 | }
152 |
153 |
154 | /**
155 | * 批量窃取节点,从尾部进行
156 | * @param taskArr
157 | * @return
158 | */
159 | CBool trySteal(std::vector& taskArr, int maxStealBatchSize) {
160 | bool result = false;
161 | if (!deque_.empty() && lock_.try_lock()) {
162 | while (!deque_.empty() && maxStealBatchSize--) {
163 | taskArr.emplace_back(std::forward(deque_.back()));
164 | deque_.pop_back();
165 | result = true;
166 | }
167 | lock_.unlock();
168 | }
169 |
170 | return result; // 如果非空,表示盗取成功
171 | }
172 |
173 | UWorkStealingQueue() = default;
174 |
175 | CGRAPH_NO_ALLOWED_COPY(UWorkStealingQueue)
176 |
177 | private:
178 | std::deque deque_; // 存放任务的双向队列
179 | std::mutex lock_; // 用于处理deque_的锁
180 | };
181 |
182 | CGRAPH_NAMESPACE_END
183 |
184 | #endif //CGRAPH_UWORKSTEALINGQUEUE_H
185 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Semaphore/USemaphore.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: USemaphore.h
5 | @Time: 2023/10/9 22:01
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_USEMAPHORE_H
10 | #define CGRAPH_USEMAPHORE_H
11 |
12 | CGRAPH_NAMESPACE_BEGIN
13 |
14 | #include
15 | #include
16 |
17 | #include "../UThreadObject.h"
18 |
19 | class USemaphore : public UThreadObject {
20 | public:
21 | /**
22 | * 触发一次信号
23 | */
24 | CVoid signal() {
25 | CGRAPH_UNIQUE_LOCK lk(mutex_);
26 | cnt_++;
27 | if (cnt_ <= 0) {
28 | cv_.notify_one();
29 | }
30 | }
31 |
32 | /**
33 | * 等待信号触发
34 | */
35 | CVoid wait() {
36 | CGRAPH_UNIQUE_LOCK lk(mutex_);
37 | cnt_--;
38 | if (cnt_ < 0) {
39 | cv_.wait(lk);
40 | }
41 | }
42 |
43 | private:
44 | CInt cnt_ = 0; // 记录当前的次数
45 | std::mutex mutex_;
46 | std::condition_variable cv_;
47 | };
48 |
49 | CGRAPH_NAMESPACE_END
50 |
51 | #endif //CGRAPH_USEMAPHORE_H
52 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Task/UTask.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: UTask.h
5 | @Time: 2021/7/2 11:32 下午
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_UTASK_H
10 | #define CGRAPH_UTASK_H
11 |
12 | #include
13 | #include
14 | #include
15 |
16 | #include "../UThreadObject.h"
17 |
18 | CGRAPH_NAMESPACE_BEGIN
19 |
20 | class UTask : public UThreadObject {
21 | struct taskBased {
22 | explicit taskBased() = default;
23 | virtual CVoid call() = 0;
24 | virtual ~taskBased() = default;
25 | };
26 |
27 | // 退化以获得实际类型,修改思路参考:https://github.com/ChunelFeng/CThreadPool/pull/3
28 | template::type>
29 | struct taskDerided : taskBased {
30 | T func_;
31 | explicit taskDerided(F&& func) : func_(std::forward(func)) {}
32 | CVoid call() override { func_(); }
33 | };
34 |
35 | public:
36 | template
37 | UTask(F&& f, int priority = 0)
38 | : impl_(new taskDerided(std::forward(f)))
39 | , priority_(priority) {}
40 |
41 | CVoid operator()() {
42 | impl_->call();
43 | }
44 |
45 | UTask() = default;
46 |
47 | UTask(UTask&& task) noexcept:
48 | impl_(std::move(task.impl_)),
49 | priority_(task.priority_) {}
50 |
51 | UTask &operator=(UTask&& task) noexcept {
52 | impl_ = std::move(task.impl_);
53 | priority_ = task.priority_;
54 | return *this;
55 | }
56 |
57 | CBool operator>(const UTask& task) const {
58 | return priority_ < task.priority_; // 新加入的,放到后面
59 | }
60 |
61 | CBool operator<(const UTask& task) const {
62 | return priority_ >= task.priority_;
63 | }
64 |
65 | CGRAPH_NO_ALLOWED_COPY(UTask)
66 |
67 | private:
68 | std::unique_ptr impl_ = nullptr;
69 | int priority_ = 0; // 任务的优先级信息
70 | };
71 |
72 |
73 | using UTaskRef = UTask &;
74 | using UTaskPtr = UTask *;
75 | using UTaskArr = std::vector;
76 | using UTaskArrRef = std::vector &;
77 |
78 | CGRAPH_NAMESPACE_END
79 |
80 | #endif //CGRAPH_UTASK_H
81 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Task/UTaskGroup.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: UTaskGroup.h
5 | @Time: 2022/1/2 2:17 下午
6 | @Desc: 任务组,用于批量提交
7 | ***************************/
8 |
9 | #ifndef CGRAPH_UTASKGROUP_H
10 | #define CGRAPH_UTASKGROUP_H
11 |
12 | #include
13 |
14 | #include "../UThreadObject.h"
15 |
16 | CGRAPH_NAMESPACE_BEGIN
17 |
18 | class UTaskGroup : public UThreadObject {
19 | public:
20 | explicit UTaskGroup() = default;
21 | CGRAPH_NO_ALLOWED_COPY(UTaskGroup)
22 |
23 | /**
24 | * 直接通过函数来申明taskGroup
25 | * @param task
26 | * @param ttl
27 | * @param onFinished
28 | */
29 | explicit UTaskGroup(CGRAPH_DEFAULT_CONST_FUNCTION_REF task,
30 | CMSec ttl = CGRAPH_MAX_BLOCK_TTL,
31 | CGRAPH_CALLBACK_CONST_FUNCTION_REF onFinished = nullptr) noexcept {
32 | this->addTask(task)
33 | ->setTtl(ttl)
34 | ->setOnFinished(onFinished);
35 | }
36 |
37 | /**
38 | * 添加一个任务
39 | * @param task
40 | */
41 | UTaskGroup* addTask(CGRAPH_DEFAULT_CONST_FUNCTION_REF task) {
42 | task_arr_.emplace_back(task);
43 | return this;
44 | }
45 |
46 | /**
47 | * 设置任务最大超时时间
48 | * @param ttl
49 | */
50 | UTaskGroup* setTtl(CMSec ttl) {
51 | this->ttl_ = ttl;
52 | return this;
53 | }
54 |
55 | /**
56 | * 设置执行完成后的回调函数
57 | * @param onFinished
58 | * @return
59 | */
60 | UTaskGroup* setOnFinished(CGRAPH_CALLBACK_CONST_FUNCTION_REF onFinished) {
61 | this->on_finished_ = onFinished;
62 | return this;
63 | }
64 |
65 | /**
66 | * 获取最大超时时间信息
67 | * @return
68 | */
69 | CMSec getTtl() const {
70 | return this->ttl_;
71 | }
72 |
73 | /**
74 | * 清空任务组
75 | */
76 | CVoid clear() {
77 | task_arr_.clear();
78 | }
79 |
80 | /**
81 | * 获取任务组大小
82 | * @return
83 | */
84 | CSize getSize() const {
85 | auto size = task_arr_.size();
86 | return size;
87 | }
88 |
89 | private:
90 | std::vector task_arr_; // 任务消息
91 | CMSec ttl_ = CGRAPH_MAX_BLOCK_TTL; // 任务组最大执行耗时(如果是0的话,则表示不阻塞)
92 | CGRAPH_CALLBACK_FUNCTION on_finished_ = nullptr; // 执行函数任务结束
93 |
94 | friend class UThreadPool;
95 | };
96 |
97 | using UTaskGroupPtr = UTaskGroup *;
98 | using UTaskGroupRef = UTaskGroup &;
99 |
100 | CGRAPH_NAMESPACE_END
101 |
102 | #endif //CGRAPH_UTASKGROUP_H
103 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Task/UTaskInclude.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: UTaskInclude.h
5 | @Time: 2022/1/12 9:34 下午
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_UTASKINCLUDE_H
10 | #define CGRAPH_UTASKINCLUDE_H
11 |
12 | #include "UTask.h"
13 | #include "UTaskGroup.h"
14 |
15 | #endif //CGRAPH_UTASKINCLUDE_H
16 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Thread/UThreadBase.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: UThreadBase.h
5 | @Time: 2021/7/2 11:24 下午
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_UTHREADBASE_H
10 | #define CGRAPH_UTHREADBASE_H
11 |
12 | #include
13 |
14 | #include "../UThreadObject.h"
15 | #include "../Queue/UQueueInclude.h"
16 | #include "../Task/UTaskInclude.h"
17 |
18 |
19 | CGRAPH_NAMESPACE_BEGIN
20 |
21 | class UThreadBase : public UThreadObject {
22 | protected:
23 | explicit UThreadBase() {
24 | done_ = true;
25 | is_init_ = false;
26 | is_running_ = false;
27 | pool_task_queue_ = nullptr;
28 | pool_priority_task_queue_ = nullptr;
29 | config_ = nullptr;
30 | total_task_num_ = 0;
31 | }
32 |
33 |
34 | ~UThreadBase() override {
35 | reset();
36 | }
37 |
38 |
39 | /**
40 | * 所有线程类的 destroy 函数应该是一样的
41 | * 但是init函数不一样,因为线程构造函数不同
42 | * @return
43 | */
44 | CStatus destroy() override {
45 | CGRAPH_FUNCTION_BEGIN
46 | CGRAPH_ASSERT_INIT(true)
47 |
48 | reset();
49 | CGRAPH_FUNCTION_END
50 | }
51 |
52 |
53 | /**
54 | * 从线程池的队列中,获取任务
55 | * @param task
56 | * @return
57 | */
58 | virtual bool popPoolTask(UTaskRef task) {
59 | bool result = pool_task_queue_->tryPop(task);
60 | if (!result && CGRAPH_THREAD_TYPE_SECONDARY == type_) {
61 | // 如果辅助线程没有获取到的话,还需要再尝试从长时间任务队列中,获取一次
62 | result = pool_priority_task_queue_->tryPop(task);
63 | }
64 | return result;
65 | }
66 |
67 |
68 | /**
69 | * 从线程池的队列中中,获取批量任务
70 | * @param tasks
71 | * @return
72 | */
73 | virtual bool popPoolTask(UTaskArrRef tasks) {
74 | bool result = pool_task_queue_->tryPop(tasks, config_->max_pool_batch_size_);
75 | if (!result && CGRAPH_THREAD_TYPE_SECONDARY == type_) {
76 | result = pool_priority_task_queue_->tryPop(tasks, 1); // 从优先队列里,最多pop出来一个
77 | }
78 | return result;
79 | }
80 |
81 |
82 | /**
83 | * 执行单个任务
84 | * @param task
85 | */
86 | CVoid runTask(UTask& task) {
87 | is_running_ = true;
88 | task();
89 | total_task_num_++;
90 | is_running_ = false;
91 | }
92 |
93 |
94 | /**
95 | * 批量执行任务
96 | * @param tasks
97 | */
98 | CVoid runTasks(UTaskArr& tasks) {
99 | is_running_ = true;
100 | for (auto& task : tasks) {
101 | task();
102 | }
103 | total_task_num_ += tasks.size();
104 | is_running_ = false;
105 | }
106 |
107 |
108 | /**
109 | * 清空所有任务内容
110 | */
111 | CVoid reset() {
112 | done_ = false;
113 | if (thread_.joinable()) {
114 | thread_.join(); // 等待线程结束
115 | }
116 | is_init_ = false;
117 | is_running_ = false;
118 | total_task_num_ = 0;
119 | }
120 |
121 | /**
122 | * 执行单个消息
123 | * @return
124 | */
125 | virtual CVoid processTask() = 0;
126 |
127 |
128 | /**
129 | * 获取批量执行task信息
130 | */
131 | virtual CVoid processTasks() = 0;
132 |
133 |
134 | /**
135 | * 循环处理任务
136 | * @return
137 | */
138 | CStatus loopProcess() {
139 | CGRAPH_FUNCTION_BEGIN
140 | CGRAPH_ASSERT_NOT_NULL(config_)
141 |
142 | if (config_->batch_task_enable_) {
143 | while (done_) {
144 | processTasks(); // 批量任务获取执行接口
145 | }
146 | } else {
147 | while (done_) {
148 | processTask(); // 单个任务获取执行接口
149 | }
150 | }
151 |
152 | CGRAPH_FUNCTION_END
153 | }
154 |
155 |
156 | /**
157 | * 设置线程优先级,仅针对非windows平台使用
158 | */
159 | CVoid setSchedParam() {
160 | #ifndef _WIN32
161 | int priority = CGRAPH_THREAD_SCHED_OTHER;
162 | int policy = CGRAPH_THREAD_MIN_PRIORITY;
163 | if (type_ == CGRAPH_THREAD_TYPE_PRIMARY) {
164 | priority = config_->primary_thread_priority_;
165 | policy = config_->primary_thread_policy_;
166 | } else if (type_ == CGRAPH_THREAD_TYPE_SECONDARY) {
167 | priority = config_->secondary_thread_priority_;
168 | policy = config_->secondary_thread_policy_;
169 | }
170 |
171 | auto handle = thread_.native_handle();
172 | sched_param param = { calcPriority(priority) };
173 | int ret = pthread_setschedparam(handle, calcPolicy(policy), ¶m);
174 | if (0 != ret) {
175 | CGRAPH_ECHO("warning : set thread sched param failed, system error code is [%d]", ret);
176 | }
177 | #endif
178 | }
179 |
180 | /**
181 | * 设置线程亲和性,仅针对linux系统
182 | */
183 | CVoid setAffinity(int index) {
184 | #if defined(__linux__) && !defined(__ANDROID__)
185 | if (!config_->bind_cpu_enable_ || CGRAPH_CPU_NUM == 0 || index < 0) {
186 | return;
187 | }
188 |
189 | cpu_set_t mask;
190 | CPU_ZERO(&mask);
191 | CPU_SET(index % CGRAPH_CPU_NUM, &mask);
192 |
193 | auto handle = thread_.native_handle();
194 | int ret = pthread_setaffinity_np(handle, sizeof(cpu_set_t), &mask);
195 | if (0 != ret) {
196 | CGRAPH_ECHO("warning : set thread affinity failed, system error code is [%d]", ret);
197 | }
198 | #endif
199 | }
200 |
201 |
202 | private:
203 | /**
204 | * 设定计算线程调度策略信息,
205 | * 非OTHER/RR/FIFO对应数值,统一返回OTHER类型
206 | * @param policy
207 | * @return
208 | */
209 | static int calcPolicy(int policy) {
210 | return (CGRAPH_THREAD_SCHED_OTHER == policy
211 | || CGRAPH_THREAD_SCHED_RR == policy
212 | || CGRAPH_THREAD_SCHED_FIFO == policy)
213 | ? policy : CGRAPH_THREAD_SCHED_OTHER;
214 | }
215 |
216 |
217 | /**
218 | * 设定线程优先级信息
219 | * 超过[min,max]范围,统一设置为min值
220 | * @param priority
221 | * @return
222 | */
223 | static int calcPriority(int priority) {
224 | return (priority >= CGRAPH_THREAD_MIN_PRIORITY
225 | && priority <= CGRAPH_THREAD_MAX_PRIORITY)
226 | ? priority : CGRAPH_THREAD_MIN_PRIORITY;
227 | }
228 |
229 |
230 | protected:
231 | bool done_; // 线程状态标记
232 | bool is_init_; // 标记初始化状态
233 | bool is_running_; // 是否正在执行
234 | int type_ = 0; // 用于区分线程类型(主线程、辅助线程)
235 | unsigned long total_task_num_ = 0; // 处理的任务的数字
236 |
237 | UAtomicQueue* pool_task_queue_; // 用于存放线程池中的普通任务
238 | UAtomicPriorityQueue* pool_priority_task_queue_; // 用于存放线程池中的包含优先级任务的队列,仅辅助线程可以执行
239 | UThreadPoolConfigPtr config_ = nullptr; // 配置参数信息
240 | std::thread thread_; // 线程类
241 | };
242 |
243 | CGRAPH_NAMESPACE_END
244 |
245 | #endif //CGRAPH_UTHREADBASE_H
246 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Thread/UThreadInclude.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: UThreadInclude.h
5 | @Time: 2022/1/12 11:09 下午
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_UTHREADINCLUDE_H
10 | #define CGRAPH_UTHREADINCLUDE_H
11 |
12 | #include "UThreadPrimary.h"
13 | #include "UThreadSecondary.h"
14 |
15 | #endif //CGRAPH_UTHREADINCLUDE_H
16 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Thread/UThreadPrimary.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: UThreadPrimary.h
5 | @Time: 2021/7/8 11:02 下午
6 | @Desc: 核心线程,处理任务中
7 | ***************************/
8 |
9 | #ifndef CGRAPH_UTHREADPRIMARY_H
10 | #define CGRAPH_UTHREADPRIMARY_H
11 |
12 | #include
13 | #include
14 |
15 | #include "UThreadBase.h"
16 |
17 | CGRAPH_NAMESPACE_BEGIN
18 |
19 | class UThreadPrimary : public UThreadBase {
20 | protected:
21 | explicit UThreadPrimary() {
22 | index_ = CGRAPH_SECONDARY_THREAD_COMMON_ID;
23 | pool_threads_ = nullptr;
24 | type_ = CGRAPH_THREAD_TYPE_PRIMARY;
25 | }
26 |
27 |
28 | CStatus init() override {
29 | CGRAPH_FUNCTION_BEGIN
30 | CGRAPH_ASSERT_INIT(false)
31 | CGRAPH_ASSERT_NOT_NULL(config_)
32 |
33 | is_init_ = true;
34 | buildStealTargets();
35 | thread_ = std::move(std::thread(&UThreadPrimary::run, this));
36 | setSchedParam();
37 | setAffinity(index_);
38 | CGRAPH_FUNCTION_END
39 | }
40 |
41 |
42 | /**
43 | * 注册线程池相关内容,需要在init之前使用
44 | * @param index
45 | * @param poolTaskQueue
46 | * @param poolThreads
47 | * @param config
48 | */
49 | CStatus setThreadPoolInfo(int index,
50 | UAtomicQueue* poolTaskQueue,
51 | std::vector* poolThreads,
52 | UThreadPoolConfigPtr config) {
53 | CGRAPH_FUNCTION_BEGIN
54 | CGRAPH_ASSERT_INIT(false) // 初始化之前,设置参数
55 | CGRAPH_ASSERT_NOT_NULL(poolTaskQueue, poolThreads, config)
56 |
57 | this->index_ = index;
58 | this->pool_task_queue_ = poolTaskQueue;
59 | this->pool_threads_ = poolThreads;
60 | this->config_ = config;
61 | CGRAPH_FUNCTION_END
62 | }
63 |
64 |
65 | /**
66 | * 线程执行函数
67 | * @return
68 | */
69 | CStatus run() final {
70 | CGRAPH_FUNCTION_BEGIN
71 | CGRAPH_ASSERT_INIT(true)
72 | CGRAPH_ASSERT_NOT_NULL(pool_threads_)
73 |
74 | /**
75 | * 线程池中任何一个primary线程为null都不可以执行
76 | * 防止线程初始化失败的情况,导致的崩溃
77 | * 理论不会走到这个判断逻辑里面
78 | */
79 | if (std::any_of(pool_threads_->begin(), pool_threads_->end(),
80 | [](UThreadPrimary* thd) {
81 | return nullptr == thd;
82 | })) {
83 | CGRAPH_RETURN_ERROR_STATUS("primary thread is null")
84 | }
85 |
86 | status = loopProcess();
87 | CGRAPH_FUNCTION_END
88 | }
89 |
90 |
91 | CVoid processTask() override {
92 | UTask task;
93 | if (popTask(task) || popPoolTask(task) || stealTask(task)) {
94 | runTask(task);
95 | } else {
96 | fatWait();
97 | }
98 | }
99 |
100 |
101 | CVoid processTasks() override {
102 | UTaskArr tasks;
103 | if (popTask(tasks) || popPoolTask(tasks) || stealTask(tasks)) {
104 | // 尝试从主线程中获取/盗取批量task,如果成功,则依次执行
105 | runTasks(tasks);
106 | } else {
107 | fatWait();
108 | }
109 | }
110 |
111 |
112 | /**
113 | * 如果总是进入无task的状态,则开始休眠
114 | * 休眠一定时间后,然后恢复执行状态,避免出现
115 | */
116 | CVoid fatWait() {
117 | cur_empty_epoch_++;
118 | std::this_thread::yield();
119 | if (cur_empty_epoch_ >= config_->primary_thread_busy_epoch_) {
120 | CGRAPH_UNIQUE_LOCK lk(mutex_);
121 | cv_.wait_for(lk, std::chrono::milliseconds(config_->primary_thread_empty_interval_));
122 | cur_empty_epoch_ = 0;
123 | }
124 | }
125 |
126 |
127 | /**
128 | * 依次push到任一队列里。如果都失败,则yield,然后重新push
129 | * @param task
130 | * @return
131 | */
132 | CVoid pushTask(UTask&& task) {
133 | while (!(primary_queue_.tryPush(std::move(task))
134 | || secondary_queue_.tryPush(std::move(task)))) {
135 | std::this_thread::yield();
136 | }
137 | cv_.notify_one();
138 | }
139 |
140 |
141 | /**
142 | * 从本地弹出一个任务
143 | * @param task
144 | * @return
145 | */
146 | bool popTask(UTaskRef task) {
147 | return primary_queue_.tryPop(task) || secondary_queue_.tryPop(task);
148 | }
149 |
150 |
151 | /**
152 | * 从本地弹出一批任务
153 | * @param tasks
154 | * @return
155 | */
156 | bool popTask(UTaskArrRef tasks) {
157 | CBool result = primary_queue_.tryPop(tasks, config_->max_local_batch_size_);
158 | auto leftSize = config_->max_local_batch_size_ - tasks.size();
159 | if (leftSize > 0) {
160 | // 如果凑齐了,就不需要了。没凑齐的话,就继续
161 | result |= (secondary_queue_.tryPop(tasks, leftSize));
162 | }
163 | return result;
164 | }
165 |
166 |
167 | /**
168 | * 从其他线程窃取一个任务
169 | * @param task
170 | * @return
171 | */
172 | bool stealTask(UTaskRef task) {
173 | if (unlikely(pool_threads_->size() < config_->default_thread_size_)) {
174 | /**
175 | * 线程池还未初始化完毕的时候,无法进行steal。
176 | * 确保程序安全运行。
177 | */
178 | return false;
179 | }
180 |
181 | /**
182 | * 窃取的时候,仅从相邻的primary线程中窃取
183 | * 待窃取相邻的数量,不能超过默认primary线程数
184 | */
185 | for (auto& target : steal_targets_) {
186 | /**
187 | * 从线程中周围的thread中,窃取任务。
188 | * 如果成功,则返回true,并且执行任务。
189 | * steal 的时候,先从第二个队列里偷,从而降低触碰锁的概率
190 | */
191 | if (likely((*pool_threads_)[target])
192 | && (((*pool_threads_)[target])->secondary_queue_.trySteal(task))
193 | || ((*pool_threads_)[target])->primary_queue_.trySteal(task)) {
194 | return true;
195 | }
196 | }
197 |
198 | return false;
199 | }
200 |
201 |
202 | /**
203 | * 从其他线程盗取一批任务
204 | * @param tasks
205 | * @return
206 | */
207 | bool stealTask(UTaskArrRef tasks) {
208 | if (unlikely(pool_threads_->size() != config_->default_thread_size_)) {
209 | return false;
210 | }
211 |
212 | for (auto& target : steal_targets_) {
213 | if (likely((*pool_threads_)[target])) {
214 | bool result = ((*pool_threads_)[target])->secondary_queue_.trySteal(tasks, config_->max_steal_batch_size_);
215 | auto leftSize = config_->max_steal_batch_size_ - tasks.size();
216 | if (leftSize > 0) {
217 | result |= ((*pool_threads_)[target])->primary_queue_.trySteal(tasks, leftSize);
218 | }
219 |
220 | if (result) {
221 | /**
222 | * 在这里,我们对模型进行了简化。实现的思路是:
223 | * 尝试从邻居主线程(先secondary,再primary)中,获取 x(=max_steal_batch_size_) 个task,
224 | * 如果从某一个邻居中,获取了 y(<=x) 个task,则也终止steal的流程
225 | * 且如果如果有一次批量steal成功,就认定成功
226 | */
227 | return true;
228 | }
229 | }
230 | }
231 |
232 | return false;
233 | }
234 |
235 |
236 | /**
237 | * 构造 steal 范围的 target,避免每次盗取的时候,重复计算
238 | * @return
239 | */
240 | CVoid buildStealTargets() {
241 | steal_targets_.clear();
242 | for (int i = 0; i < config_->calcStealRange(); i++) {
243 | auto target = (index_ + i + 1) % config_->default_thread_size_;
244 | steal_targets_.push_back(target);
245 | }
246 | steal_targets_.shrink_to_fit();
247 | }
248 |
249 | private:
250 | int index_; // 线程index
251 | int cur_empty_epoch_ = 0; // 当前空转的轮数信息
252 | UWorkStealingQueue primary_queue_; // 内部队列信息
253 | UWorkStealingQueue secondary_queue_; // 第二个队列,用于减少触锁概率,提升性能
254 | std::vector* pool_threads_; // 用于存放线程池中的线程信息
255 | std::vector steal_targets_; // 被偷的目标信息
256 |
257 | std::mutex mutex_;
258 | std::condition_variable cv_;
259 |
260 | friend class UThreadPool;
261 | friend class UAllocator;
262 | };
263 |
264 | using UThreadPrimaryPtr = UThreadPrimary *;
265 |
266 | CGRAPH_NAMESPACE_END
267 |
268 | #endif //CGRAPH_UTHREADPRIMARY_H
269 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/Thread/UThreadSecondary.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: UThreadSecondary.h
5 | @Time: 2021/7/8 11:02 下午
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_UTHREADSECONDARY_H
10 | #define CGRAPH_UTHREADSECONDARY_H
11 |
12 | #include "UThreadBase.h"
13 |
14 | CGRAPH_NAMESPACE_BEGIN
15 |
16 | class UThreadSecondary : public UThreadBase {
17 | public:
18 | explicit UThreadSecondary() {
19 | cur_ttl_ = 0;
20 | type_ = CGRAPH_THREAD_TYPE_SECONDARY;
21 | }
22 |
23 |
24 | protected:
25 | CStatus init() override {
26 | CGRAPH_FUNCTION_BEGIN
27 | CGRAPH_ASSERT_INIT(false)
28 | CGRAPH_ASSERT_NOT_NULL(config_)
29 |
30 | cur_ttl_ = config_->secondary_thread_ttl_;
31 | is_init_ = true;
32 | thread_ = std::move(std::thread(&UThreadSecondary::run, this));
33 | setSchedParam();
34 | CGRAPH_FUNCTION_END
35 | }
36 |
37 |
38 | /**
39 | * 设置pool的信息
40 | * @param poolTaskQueue
41 | * @param poolPriorityTaskQueue
42 | * @param config
43 | * @return
44 | */
45 | CStatus setThreadPoolInfo(UAtomicQueue* poolTaskQueue,
46 | UAtomicPriorityQueue* poolPriorityTaskQueue,
47 | UThreadPoolConfigPtr config) {
48 | CGRAPH_FUNCTION_BEGIN
49 | CGRAPH_ASSERT_INIT(false) // 初始化之前,设置参数
50 | CGRAPH_ASSERT_NOT_NULL(poolTaskQueue, poolPriorityTaskQueue, config)
51 |
52 | this->pool_task_queue_ = poolTaskQueue;
53 | this->pool_priority_task_queue_ = poolPriorityTaskQueue;
54 | this->config_ = config;
55 | CGRAPH_FUNCTION_END
56 | }
57 |
58 |
59 | CStatus run() final {
60 | CGRAPH_FUNCTION_BEGIN
61 | CGRAPH_ASSERT_INIT(true)
62 |
63 | status = loopProcess();
64 | CGRAPH_FUNCTION_END
65 | }
66 |
67 |
68 | CVoid processTask() override {
69 | UTask task;
70 | if (popPoolTask(task)) {
71 | runTask(task);
72 | } else {
73 | // 如果单次无法获取,则稍加等待
74 | waitRunTask(config_->queue_emtpy_interval_);
75 | }
76 | }
77 |
78 |
79 | CVoid processTasks() override {
80 | UTaskArr tasks;
81 | if (popPoolTask(tasks)) {
82 | runTasks(tasks);
83 | } else {
84 | waitRunTask(config_->queue_emtpy_interval_);
85 | }
86 | }
87 |
88 |
89 | /**
90 | * 有等待的执行任务
91 | * @param ms
92 | * @return
93 | * @notice 目的是降低cpu的占用率
94 | */
95 | CVoid waitRunTask(CMSec ms) {
96 | auto task = this->pool_task_queue_->popWithTimeout(ms);
97 | if (nullptr != task) {
98 | (*task)();
99 | }
100 | }
101 |
102 |
103 | /**
104 | * 判断本线程是否需要被自动释放
105 | * @return
106 | */
107 | bool freeze() {
108 | if (likely(is_running_)) {
109 | cur_ttl_++;
110 | cur_ttl_ = std::min(cur_ttl_, config_->secondary_thread_ttl_);
111 | } else {
112 | cur_ttl_--; // 如果当前线程没有在执行,则ttl-1
113 | }
114 |
115 | return cur_ttl_ <= 0 && done_; // 必须是正在执行的线程,才可以被回收
116 | }
117 |
118 | private:
119 | int cur_ttl_ = 0; // 当前最大生存周期
120 |
121 | friend class UThreadPool;
122 | };
123 |
124 | using UThreadSecondaryPtr = UThreadSecondary *;
125 |
126 | CGRAPH_NAMESPACE_END
127 |
128 | #endif // CGRAPH_UTHREADSECONDARY_H
129 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/UThreadObject.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: CThreadObject.h
5 | @Time: 2021/7/2 10:39 下午
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_UTHREADOBJECT_H
10 | #define CGRAPH_UTHREADOBJECT_H
11 |
12 | #include "../UtilsObject.h"
13 | #include "UThreadPoolDefine.h"
14 |
15 | CGRAPH_NAMESPACE_BEGIN
16 |
17 | class UThreadObject : public UtilsObject {
18 | protected:
19 | /**
20 | * 部分thread中的算子,可以不实现run方法
21 | * @return
22 | */
23 | CStatus run() override {
24 | CGRAPH_NO_SUPPORT
25 | }
26 | };
27 |
28 | CGRAPH_NAMESPACE_END
29 |
30 | #endif //CGRAPH_UTHREADOBJECT_H
31 |
--------------------------------------------------------------------------------
/src/UtilsCtrl/ThreadPool/UThreadPool.h:
--------------------------------------------------------------------------------
1 | /***************************
2 | @Author: Chunel
3 | @Contact: chunel@foxmail.com
4 | @File: UThreadPool.h
5 | @Time: 2021/7/4 1:34 下午
6 | @Desc:
7 | ***************************/
8 |
9 | #ifndef CGRAPH_UTHREADPOOL_H
10 | #define CGRAPH_UTHREADPOOL_H
11 |
12 | #include
13 | #include
14 | #include