diff --git a/CMakeLists.txt b/CMakeLists.txt index 885c5e7..28a3c7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ message("* * * * * * * * * * * * * * * * *") cmake_minimum_required(VERSION 3.2.5) -project(CThreadPool VERSION 1.1.0) +project(CThreadPool VERSION 1.2.0) set(CMAKE_CXX_STANDARD 11) diff --git a/README.md b/README.md index 07421b8..b7e0f43 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,9 @@ int main() { [2022.10.11 - v1.1.0 - [MirrorYuChen](https://github.com/MirrorYuChen)] * 提供针对C++11版本的支持 +[2023.03.07 - v1.2.0 - Chunel] +* 优化windows版本功能 + ------------ #### 附录-2. 联系方式 * 微信: ChunelFeng diff --git a/src/CBasic/CBasicInclude.h b/src/CBasic/CBasicInclude.h index d694855..517c195 100644 --- a/src/CBasic/CBasicInclude.h +++ b/src/CBasic/CBasicInclude.h @@ -15,6 +15,7 @@ #include "CStatus.h" #include "CException.h" #include "CBasicDefine.h" -#include "CInfoDefine.h" +#include "CStrDefine.h" +#include "CStdEx.h" #endif //CGRAPH_CBASICINCLUDE_H diff --git a/src/CBasic/CException.h b/src/CBasic/CException.h index ada360a..611034d 100644 --- a/src/CBasic/CException.h +++ b/src/CBasic/CException.h @@ -12,7 +12,7 @@ #include #include -#include "CInfoDefine.h" +#include "CStrDefine.h" CGRAPH_NAMESPACE_BEGIN diff --git a/src/CBasic/CFuncType.h b/src/CBasic/CFuncType.h index 9f68dd3..4e0732b 100644 --- a/src/CBasic/CFuncType.h +++ b/src/CBasic/CFuncType.h @@ -11,7 +11,7 @@ #include -#include "CInfoDefine.h" +#include "CStrDefine.h" #include "CValType.h" CGRAPH_NAMESPACE_BEGIN diff --git a/src/CBasic/CInfoDefine.h b/src/CBasic/CInfoDefine.h deleted file mode 100644 index e004ab8..0000000 --- a/src/CBasic/CInfoDefine.h +++ /dev/null @@ -1,22 +0,0 @@ -/*************************** -@Author: Chunel -@Contact: chunel@foxmail.com -@File: CInfoDefine.h -@Time: 2022/4/16 14:01 -@Desc: -***************************/ - -#ifndef CGRAPH_CINFODEFINE_H -#define CGRAPH_CINFODEFINE_H - -#include "CBasicDefine.h" - -CGRAPH_NAMESPACE_BEGIN - -static const char* CGRAPH_EMPTY = ""; -static const char* CGRAPH_BASIC_EXCEPTION = "CGraph Exception"; -static const char* CGRAPH_FUNCTION_NO_SUPPORT = "function no support"; - -CGRAPH_NAMESPACE_END - -#endif //CGRAPH_CINFODEFINE_H diff --git a/src/CBasic/CObject.h b/src/CBasic/CObject.h index 8ccbe46..9f98b4c 100644 --- a/src/CBasic/CObject.h +++ b/src/CBasic/CObject.h @@ -35,7 +35,7 @@ public: virtual CStatus run() = 0; /** - * 释放函数(对应原先deinit函数) + * 释放函数 */ virtual CStatus destroy() { CGRAPH_EMPTY_FUNCTION diff --git a/src/CBasic/CStatus.h b/src/CBasic/CStatus.h index dde3ea6..731e345 100644 --- a/src/CBasic/CStatus.h +++ b/src/CBasic/CStatus.h @@ -12,9 +12,17 @@ #include #include "CBasicDefine.h" +#include "CStrDefine.h" CGRAPH_NAMESPACE_BEGIN +/** + * 说明: + * 返回值为0,表示正常逻辑 + * 返回值为正整数,表示warning逻辑,程序仍会继续执行 + * 返回值为负整数,表示error逻辑,程序终止执行 + * 自定义返回值,请务必遵守以上约定 + */ static const int STATUS_OK = 0; /** 正常流程返回值 */ static const int STATUS_ERR = -1; /** 异常流程返回值 */ static const char* STATUS_ERROR_INFO_CONNECTOR = " && "; /** 多异常信息连接符号 */ @@ -79,6 +87,14 @@ public: } /** + * 恢复数据 + */ + void reset() { + error_code_ = STATUS_OK; + error_info_ = CGRAPH_EMPTY; + } + + /** * 判断当前状态是否可行 * @return */ @@ -94,6 +110,22 @@ public: return error_code_ < STATUS_OK; // 约定异常信息,均为负值 } + /** + * 判断当前状态是否有异常 + * @return + */ + [[nodiscard]] bool isNotErr() const { + return error_code_ >= STATUS_OK; + } + + /** + * 判断当前状态,不是ok的(包含error 和 warning) + * @return + */ + [[nodiscard]] bool isNotOK() const { + return error_code_ != STATUS_OK; + } + private: int error_code_ { STATUS_OK }; // 错误码信息 std::string error_info_; // 错误信息描述 diff --git a/src/CBasic/CStdEx.h b/src/CBasic/CStdEx.h new file mode 100644 index 0000000..ec0b2f1 --- /dev/null +++ b/src/CBasic/CStdEx.h @@ -0,0 +1,29 @@ +/*************************** +@Author: Chunel +@Contact: chunel@foxmail.com +@File: CStdEx.h +@Time: 2023/1/31 23:15 +@Desc: +***************************/ + +#ifndef CGRAPH_CSTDEX_H +#define CGRAPH_CSTDEX_H + +#include +#include + +CGRAPH_NAMESPACE_BEGIN + +// 兼容 std::enable_if_t 的语法 +template +using c_enable_if_t = typename std::enable_if::type; + +// 兼容 std::make_unique 的语法 +template +typename std::unique_ptr c_make_unique(Args&&... args) { + return std::unique_ptr(new T(std::forward(args)...)); +} + +CGRAPH_NAMESPACE_END + +#endif //CGRAPH_CSTDEX_H diff --git a/src/CBasic/CStrDefine.h b/src/CBasic/CStrDefine.h new file mode 100644 index 0000000..9b66209 --- /dev/null +++ b/src/CBasic/CStrDefine.h @@ -0,0 +1,24 @@ +/*************************** +@Author: Chunel +@Contact: chunel@foxmail.com +@File: CInfoDefine.h +@Time: 2022/4/16 14:01 +@Desc: +***************************/ + +#ifndef CGRAPH_CSTRDEFINE_H +#define CGRAPH_CSTRDEFINE_H + +#include "CBasicDefine.h" + +CGRAPH_NAMESPACE_BEGIN + +static const char* CGRAPH_EMPTY = ""; +static const char* CGRAPH_DEFAULT = "default"; +static const char* CGRAPH_UNKNOWN = "unknown"; +static const char* CGRAPH_BASIC_EXCEPTION = "CGraph default exception"; +static const char* CGRAPH_FUNCTION_NO_SUPPORT = "CGraph function no support"; + +CGRAPH_NAMESPACE_END + +#endif //CGRAPH_CSTRDEFINE_H diff --git a/src/UtilsCtrl/ThreadPool/Lock/ULockInclude.h b/src/UtilsCtrl/ThreadPool/Lock/ULockInclude.h new file mode 100644 index 0000000..dc3b482 --- /dev/null +++ b/src/UtilsCtrl/ThreadPool/Lock/ULockInclude.h @@ -0,0 +1,14 @@ +/*************************** +@Author: Chunel +@Contact: chunel@foxmail.com +@File: ULockInclude.h +@Time: 2023/2/21 22:19 +@Desc: +***************************/ + +#ifndef CGRAPH_ULOCKINCLUDE_H +#define CGRAPH_ULOCKINCLUDE_H + +#include "USpinLock.h" + +#endif //CGRAPH_ULOCKINCLUDE_H diff --git a/src/UtilsCtrl/ThreadPool/Lock/USpinLock.h b/src/UtilsCtrl/ThreadPool/Lock/USpinLock.h new file mode 100644 index 0000000..1615f9b --- /dev/null +++ b/src/UtilsCtrl/ThreadPool/Lock/USpinLock.h @@ -0,0 +1,51 @@ +/*************************** +@Author: Chunel +@Contact: chunel@foxmail.com +@File: USpinLock.h +@Time: 2023/2/21 22:17 +@Desc: +***************************/ + +#ifndef CGRAPH_USPINLOCK_H +#define CGRAPH_USPINLOCK_H + +#include + +#include "../UThreadObject.h" + +CGRAPH_NAMESPACE_BEGIN + +class USpinLock : public UThreadObject { +public: + /** + * 加锁 + */ + CVoid lock() { + // memory_order_acquire 后面访存指令勿重排至此条指令之前 + while (flag_.test_and_set(std::memory_order_acquire)) { + } + } + + /** + * 解锁 + */ + CVoid unlock() { + // memory_order_release 前面访存指令勿重排到此条指令之后 + flag_.clear(std::memory_order_release); + } + + /** + * 尝试加锁。若未加锁,会上锁 + * @return + */ + CBool tryLock() { + return !flag_.test_and_set(); + } + +private: + std::atomic_flag flag_ = ATOMIC_FLAG_INIT; // 标志位 +}; + +CGRAPH_NAMESPACE_END + +#endif //CGRAPH_USPINLOCK_H diff --git a/src/UtilsCtrl/ThreadPool/Queue/UAtomicPriorityQueue.h b/src/UtilsCtrl/ThreadPool/Queue/UAtomicPriorityQueue.h index deaba6c..b0d4999 100644 --- a/src/UtilsCtrl/ThreadPool/Queue/UAtomicPriorityQueue.h +++ b/src/UtilsCtrl/ThreadPool/Queue/UAtomicPriorityQueue.h @@ -64,7 +64,7 @@ public: * @return */ CVoid push(T&& value, int priority) { - std::unique_ptr task(make_unique(std::move(value), priority)); + std::unique_ptr task(c_make_unique(std::move(value), priority)); CGRAPH_LOCK_GUARD lk(mutex_); priority_queue_.push(std::move(task)); } diff --git a/src/UtilsCtrl/ThreadPool/Queue/UAtomicQueue.h b/src/UtilsCtrl/ThreadPool/Queue/UAtomicQueue.h index fde4f89..e55ab66 100644 --- a/src/UtilsCtrl/ThreadPool/Queue/UAtomicQueue.h +++ b/src/UtilsCtrl/ThreadPool/Queue/UAtomicQueue.h @@ -14,6 +14,7 @@ #include #include +#include "../UThreadPoolDefine.h" #include "UQueueObject.h" CGRAPH_NAMESPACE_BEGIN @@ -103,7 +104,7 @@ public: * @param value */ CVoid push(T&& value) { - std::unique_ptr task(make_unique(std::move(value))); + std::unique_ptr task(c_make_unique(std::move(value))); CGRAPH_LOCK_GUARD lk(mutex_); queue_.push(std::move(task)); cv_.notify_one(); diff --git a/src/UtilsCtrl/ThreadPool/Queue/UAtomicRingBufferQueue.h b/src/UtilsCtrl/ThreadPool/Queue/UAtomicRingBufferQueue.h new file mode 100644 index 0000000..e30a2db --- /dev/null +++ b/src/UtilsCtrl/ThreadPool/Queue/UAtomicRingBufferQueue.h @@ -0,0 +1,129 @@ +/*************************** +@Author: Chunel +@Contact: chunel@foxmail.com +@File: UAtomicRingBufferQueue.h +@Time: 2022/10/22 22:32 +@Desc: 本 queue 仅支持单入单出模式 +***************************/ + +#ifndef CGRAPH_UATOMICRINGBUFFERQUEUE_H +#define CGRAPH_UATOMICRINGBUFFERQUEUE_H + +#include +#include + +#include "UQueueObject.h" + +CGRAPH_NAMESPACE_BEGIN + +template +class UAtomicRingBufferQueue : public UQueueObject { +public: + explicit UAtomicRingBufferQueue() { + head_ = 0; + tail_ = 0; + capacity_ = capacity; + ring_buffer_queue_.resize(capacity_); + } + + ~UAtomicRingBufferQueue() override { + clear(); + } + + /** + * 设置容量信息 + * @param size + * @return + * @notice 谨慎使用,push信息之后,不推荐使用 + */ + UAtomicRingBufferQueue* setCapacity(CUint size) { + capacity_ = size; + ring_buffer_queue_.resize(capacity_); + return this; + } + + /** + * 获取容量信息 + * @return + */ + [[nodiscard]] CUint getCapacity() const { + return capacity_; + } + + /** + * 写入信息 + * @param value + * @return + */ + template + CVoid push(const TImpl& value) { + { + CGRAPH_UNIQUE_LOCK lk(mutex_); + if (isFull()) { + push_cv_.wait(lk, [this] { return !isFull(); }); + } + + ring_buffer_queue_[tail_] = std::move(c_make_unique(value)); + tail_ = (tail_ + 1) % capacity_; + } + pop_cv_.notify_one(); + } + + /** + * 等待弹出信息 + * @param value + * @return + */ + template + CVoid waitPop(TImpl& value) { + { + CGRAPH_UNIQUE_LOCK lk(mutex_); + if (isEmpty()) { + pop_cv_.wait(lk, [this] { return !isEmpty(); }); + } + + value = (*ring_buffer_queue_[head_]); + *ring_buffer_queue_[head_] = {}; + head_ = (head_ + 1) % capacity_; + } + push_cv_.notify_one(); + } + + /** + * 清空所有的数据 + * @return + */ + CStatus clear() { + CGRAPH_FUNCTION_BEGIN + ring_buffer_queue_.resize(0); + head_ = 0; + tail_ = 0; + CGRAPH_FUNCTION_END + } + +protected: + CBool isFull() { + // 空出来一个位置,这个时候不让 tail写入 + return head_ == (tail_ + 1) % capacity_; + } + + CBool isEmpty() { + return head_ == tail_; + } + + CGRAPH_NO_ALLOWED_COPY(UAtomicRingBufferQueue) + +private: + CUint head_; // 头结点位置 + CUint tail_; // 尾结点位置 + CUint capacity_; // 环形缓冲的容量大小 + + std::condition_variable push_cv_; // 写入的条件变量。为了保持语义完整,也考虑今后多入多出的可能性,不使用 父类中的 cv_了 + std::condition_variable pop_cv_; // 读取的条件变量 + + std::vector > ring_buffer_queue_; // 环形缓冲区 +}; + +CGRAPH_NAMESPACE_END + +#endif //CGRAPH_UATOMICRINGBUFFERQUEUE_H diff --git a/src/UtilsCtrl/ThreadPool/Queue/UQueueInclude.h b/src/UtilsCtrl/ThreadPool/Queue/UQueueInclude.h index a1b070d..ade3b09 100644 --- a/src/UtilsCtrl/ThreadPool/Queue/UQueueInclude.h +++ b/src/UtilsCtrl/ThreadPool/Queue/UQueueInclude.h @@ -12,5 +12,6 @@ #include "UAtomicQueue.h" #include "UWorkStealingQueue.h" #include "UAtomicPriorityQueue.h" +#include "UAtomicRingBufferQueue.h" #endif //CGRAPH_UQUEUEINCLUDE_H diff --git a/src/UtilsCtrl/ThreadPool/Queue/UQueueObject.h b/src/UtilsCtrl/ThreadPool/Queue/UQueueObject.h index 3c2d206..75da626 100644 --- a/src/UtilsCtrl/ThreadPool/Queue/UQueueObject.h +++ b/src/UtilsCtrl/ThreadPool/Queue/UQueueObject.h @@ -11,7 +11,6 @@ #include -#include "../UThreadPoolDefine.h" #include "../UThreadObject.h" CGRAPH_NAMESPACE_BEGIN diff --git a/src/UtilsCtrl/ThreadPool/Queue/UWorkStealingQueue.h b/src/UtilsCtrl/ThreadPool/Queue/UWorkStealingQueue.h index 9a4b5a7..f2d862b 100644 --- a/src/UtilsCtrl/ThreadPool/Queue/UWorkStealingQueue.h +++ b/src/UtilsCtrl/ThreadPool/Queue/UWorkStealingQueue.h @@ -11,27 +11,25 @@ #define CGRAPH_UWORKSTEALINGQUEUE_H #include -#include #include #include "UQueueObject.h" -#include "../Task/UTask.h" +#include "../Task/UTaskInclude.h" +#include "../Lock/ULockInclude.h" CGRAPH_NAMESPACE_BEGIN class UWorkStealingQueue : public UQueueObject { public: - UWorkStealingQueue() = default; - /** * 向队列中写入信息 * @param task */ CVoid push(UTask&& task) { while (true) { - if (mutex_.try_lock()) { + if (lock_.tryLock()) { deque_.emplace_front(std::move(task)); - mutex_.unlock(); + lock_.unlock(); break; } else { std::this_thread::yield(); @@ -48,13 +46,13 @@ public: CBool tryPop(UTask& task) { // 这里不使用raii锁,主要是考虑到多线程的情况下,可能会重复进入 bool result = false; - if (mutex_.try_lock()) { + if (lock_.tryLock()) { if (!deque_.empty()) { task = std::move(deque_.front()); // 从前方弹出 deque_.pop_front(); result = true; } - mutex_.unlock(); + lock_.unlock(); } return result; @@ -70,13 +68,13 @@ public: CBool tryPop(UTaskArrRef taskArr, int maxLocalBatchSize) { bool result = false; - if (mutex_.try_lock()) { + if (lock_.tryLock()) { while (!deque_.empty() && maxLocalBatchSize--) { taskArr.emplace_back(std::move(deque_.front())); deque_.pop_front(); result = true; } - mutex_.unlock(); + lock_.unlock(); } return result; @@ -90,13 +88,13 @@ public: */ CBool trySteal(UTask& task) { bool result = false; - if (mutex_.try_lock()) { + if (lock_.tryLock()) { if (!deque_.empty()) { task = std::move(deque_.back()); // 从后方窃取 deque_.pop_back(); result = true; } - mutex_.unlock(); + lock_.unlock(); } return result; @@ -110,22 +108,25 @@ public: */ CBool trySteal(UTaskArrRef taskArr, int maxStealBatchSize) { bool result = false; - if (mutex_.try_lock()) { + if (lock_.tryLock()) { while (!deque_.empty() && maxStealBatchSize--) { taskArr.emplace_back(std::move(deque_.back())); deque_.pop_back(); result = true; } - mutex_.unlock(); + lock_.unlock(); } return result; // 如果非空,表示盗取成功 } + UWorkStealingQueue() = default; + CGRAPH_NO_ALLOWED_COPY(UWorkStealingQueue) private: - std::deque deque_; + std::deque deque_; // 存放任务的双向队列 + USpinLock lock_; // 用自旋锁处理 }; CGRAPH_NAMESPACE_END diff --git a/src/UtilsCtrl/ThreadPool/Task/UTask.h b/src/UtilsCtrl/ThreadPool/Task/UTask.h index 956eba2..8347b23 100644 --- a/src/UtilsCtrl/ThreadPool/Task/UTask.h +++ b/src/UtilsCtrl/ThreadPool/Task/UTask.h @@ -24,6 +24,7 @@ class UTask : public UThreadObject { virtual ~taskBased() = default; }; + // 退化以获得实际类型,修改思路参考:https://github.com/ChunelFeng/CThreadPool/pull/3 template::type> struct taskDerided : taskBased { T func_; @@ -38,9 +39,7 @@ public: , priority_(priority) {} CVoid operator()() { - if (likely(impl_)) { - impl_->call(); - } + impl_->call(); } UTask() = default; diff --git a/src/UtilsCtrl/ThreadPool/Thread/UThreadBase.h b/src/UtilsCtrl/ThreadPool/Thread/UThreadBase.h index 95ecc35..939442b 100644 --- a/src/UtilsCtrl/ThreadPool/Thread/UThreadBase.h +++ b/src/UtilsCtrl/ThreadPool/Thread/UThreadBase.h @@ -19,7 +19,6 @@ CGRAPH_NAMESPACE_BEGIN class UThreadBase : public UThreadObject { - protected: explicit UThreadBase() { done_ = true; @@ -59,7 +58,7 @@ protected: virtual bool popPoolTask(UTaskRef task) { bool result = pool_task_queue_->tryPop(task); if (!result && CGRAPH_THREAD_TYPE_SECONDARY == type_) { - // 如果辅助线程没有获取到的话,还需要再尝试从长时间任务队列中,获取一次。 + // 如果辅助线程没有获取到的话,还需要再尝试从长时间任务队列中,获取一次 result = pool_priority_task_queue_->tryPop(task); } return result; @@ -74,7 +73,7 @@ protected: virtual bool popPoolTask(UTaskArrRef tasks) { bool result = pool_task_queue_->tryPop(tasks, config_->max_pool_batch_size_); if (!result && CGRAPH_THREAD_TYPE_SECONDARY == type_) { - result = pool_priority_task_queue_->tryPop(tasks, 1); + result = pool_priority_task_queue_->tryPop(tasks, 1); // 从优先队列里,最多pop出来一个 } return result; } diff --git a/src/UtilsCtrl/ThreadPool/Thread/UThreadPrimary.h b/src/UtilsCtrl/ThreadPool/Thread/UThreadPrimary.h index a41cf0c..e9e5677 100644 --- a/src/UtilsCtrl/ThreadPool/Thread/UThreadPrimary.h +++ b/src/UtilsCtrl/ThreadPool/Thread/UThreadPrimary.h @@ -16,7 +16,7 @@ CGRAPH_NAMESPACE_BEGIN class UThreadPrimary : public UThreadBase { protected: explicit UThreadPrimary() { - index_ = -1; + index_ = CGRAPH_SECONDARY_THREAD_COMMON_ID; pool_threads_ = nullptr; type_ = CGRAPH_THREAD_TYPE_PRIMARY; } @@ -201,7 +201,7 @@ protected: } private: - int index_ {-1}; // 线程index + int index_ {CGRAPH_SECONDARY_THREAD_COMMON_ID}; // 线程index UWorkStealingQueue work_stealing_queue_; // 内部队列信息 std::vector* pool_threads_; // 用于存放线程池中的线程信息 diff --git a/src/UtilsCtrl/ThreadPool/UThreadObject.h b/src/UtilsCtrl/ThreadPool/UThreadObject.h index f3c26ac..a15da3c 100644 --- a/src/UtilsCtrl/ThreadPool/UThreadObject.h +++ b/src/UtilsCtrl/ThreadPool/UThreadObject.h @@ -14,7 +14,6 @@ CGRAPH_NAMESPACE_BEGIN class UThreadObject : public UtilsObject { - protected: /** * 部分thread中的算子,可以不实现run方法 diff --git a/src/UtilsCtrl/ThreadPool/UThreadPool.cpp b/src/UtilsCtrl/ThreadPool/UThreadPool.cpp index 04df234..014ea20 100644 --- a/src/UtilsCtrl/ThreadPool/UThreadPool.cpp +++ b/src/UtilsCtrl/ThreadPool/UThreadPool.cpp @@ -53,12 +53,15 @@ CStatus UThreadPool::init() { CGRAPH_FUNCTION_END } + thread_record_map_.clear(); primary_threads_.reserve(config_.default_thread_size_); for (int i = 0; i < config_.default_thread_size_; i++) { - auto ptr = CGRAPH_SAFE_MALLOC_COBJECT(UThreadPrimary) // 创建核心线程数 - + auto ptr = CGRAPH_SAFE_MALLOC_COBJECT(UThreadPrimary); // 创建核心线程数 ptr->setThreadPoolInfo(i, &task_queue_, &primary_threads_, &config_); status += ptr->init(); + + // 记录线程和匹配id信息 + thread_record_map_[(CSize)std::hash{}(ptr->thread_.get_id())] = i; primary_threads_.emplace_back(ptr); } CGRAPH_FUNCTION_CHECK_STATUS @@ -113,6 +116,17 @@ CStatus UThreadPool::submit(CGRAPH_DEFAULT_CONST_FUNCTION_REF func, CMSec ttl, } +CIndex UThreadPool::getThreadNum(CSize tid) { + int threadNum = CGRAPH_SECONDARY_THREAD_COMMON_ID; + auto result = thread_record_map_.find(tid); + if (result != thread_record_map_.end()) { + threadNum = result->second; + } + + return threadNum; +} + + CStatus UThreadPool::destroy() { CGRAPH_FUNCTION_BEGIN if (!is_init_) { @@ -121,10 +135,20 @@ CStatus UThreadPool::destroy() { // primary 线程是普通指针,需要delete for (auto &pt : primary_threads_) { - status += pt->destroy(); - CGRAPH_DELETE_PTR(pt) + status += pt->destroy(); } CGRAPH_FUNCTION_CHECK_STATUS + + /** + * 这里之所以 destroy和 delete分开两个循环执行, + * 是因为当前线程被delete后,还可能存在未被delete的主线程,来steal当前线程的任务 + * 在windows环境下,可能出现问题。 + * destroy 和 delete 分开之后,不会出现此问题。 + * 感谢 Ryan大佬(https://github.com/ryanhuang) 提供的帮助 + */ + for (auto &pt : primary_threads_) { + CGRAPH_DELETE_PTR(pt) + } primary_threads_.clear(); // secondary 线程是智能指针,不需要delete @@ -133,6 +157,7 @@ CStatus UThreadPool::destroy() { } CGRAPH_FUNCTION_CHECK_STATUS secondary_threads_.clear(); + thread_record_map_.clear(); is_init_ = false; CGRAPH_FUNCTION_END diff --git a/src/UtilsCtrl/ThreadPool/UThreadPool.h b/src/UtilsCtrl/ThreadPool/UThreadPool.h index 7f3928f..ce0d6b6 100644 --- a/src/UtilsCtrl/ThreadPool/UThreadPool.h +++ b/src/UtilsCtrl/ThreadPool/UThreadPool.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -101,6 +102,14 @@ public: CGRAPH_CALLBACK_CONST_FUNCTION_REF onFinished = nullptr); /** + * 获取根据线程id信息,获取线程num信息 + * @param tid + * @return + * @notice 辅助线程返回-1 + */ + CIndex getThreadNum(CSize tid); + + /** * 释放所有的线程信息 * @return */ @@ -130,7 +139,7 @@ protected: CGRAPH_NO_ALLOWED_COPY(UThreadPool) -protected: +private: CBool is_init_ { false }; // 是否初始化 CBool is_monitor_ { true }; // 是否需要监控 CInt cur_index_ = 0; // 记录放入的线程数 @@ -141,6 +150,7 @@ protected: std::list> secondary_threads_; // 用于记录所有的辅助线程 UThreadPoolConfig config_; // 线程池设置值 std::thread monitor_thread_; // 监控线程 + std::map thread_record_map_; // 线程记录的信息 }; using UThreadPoolPtr = UThreadPool *; diff --git a/src/UtilsCtrl/ThreadPool/UThreadPool.inl b/src/UtilsCtrl/ThreadPool/UThreadPool.inl index 8d3d4f0..61f749c 100644 --- a/src/UtilsCtrl/ThreadPool/UThreadPool.inl +++ b/src/UtilsCtrl/ThreadPool/UThreadPool.inl @@ -40,6 +40,7 @@ auto UThreadPool::commit(const FunctionType& func, CIndex index) return result; } + template auto UThreadPool::commitWithPriority(const FunctionType& func, int priority) -> std::future::type> { diff --git a/src/UtilsCtrl/ThreadPool/UThreadPoolDefine.h b/src/UtilsCtrl/ThreadPool/UThreadPoolDefine.h index 13d47db..49fdaa8 100644 --- a/src/UtilsCtrl/ThreadPool/UThreadPoolDefine.h +++ b/src/UtilsCtrl/ThreadPool/UThreadPoolDefine.h @@ -10,16 +10,18 @@ #define CGRAPH_UTHREADPOOLDEFINE_H #include - #if _LIBCPP_STD_VER >= 17 + #if __cplusplus >= 201703L #include #else # include #endif #include +#include "../UtilsDefine.h" + CGRAPH_NAMESPACE_BEGIN - #if _LIBCPP_STD_VER >= 17 + #if __cplusplus >= 201703L using CGRAPH_READ_LOCK = std::shared_lock; using CGRAPH_WRITE_LOCK = std::unique_lock; #else @@ -46,8 +48,13 @@ static const int CGRAPH_THREAD_SCHED_FIFO = 0; static const int CGRAPH_THREAD_MIN_PRIORITY = 0; // 线程最低优先级 static const int CGRAPH_THREAD_MAX_PRIORITY = 99; // 线程最高优先级 static const CMSec CGRAPH_MAX_BLOCK_TTL = 10000000; // 最大阻塞时间,单位为ms +static const CUint CGRAPH_DEFAULT_RINGBUFFER_SIZE = 1024; // 默认环形队列的大小 +const static CIndex CGRAPH_SECONDARY_THREAD_COMMON_ID = -1; // 辅助线程统一id标识 + static const int CGRAPH_DEFAULT_TASK_STRATEGY = -1; // 默认线程调度策略 static const int CGRAPH_LONG_TIME_TASK_STRATEGY = -101; // 长时间任务调度策略 +static const int CGRAPH_REGION_TASK_STRATEGY = -102; // region的调度策略 +static const int CGRAPH_EVENT_TASK_STRATEGY = -103; // event的调度策略 /** * 以下为线程池配置信息 @@ -55,18 +62,14 @@ static const int CGRAPH_LONG_TIME_TASK_STRATEGY = -101; static const int CGRAPH_DEFAULT_THREAD_SIZE = 8; // 默认主线程个数 static const int CGRAPH_SECONDARY_THREAD_SIZE = 0; // 默认开启辅助线程个数 static const int CGRAPH_MAX_THREAD_SIZE = (CGRAPH_DEFAULT_THREAD_SIZE * 2) + 1; // 最大线程个数 - #ifndef _WIN32 static const int CGRAPH_MAX_TASK_STEAL_RANGE = 2; // 盗取机制相邻范围 - #else -static const int CGRAPH_MAX_TASK_STEAL_RANGE = 0; // windows平台暂不支持任务盗取功能 - #endif static const bool CGRAPH_BATCH_TASK_ENABLE = false; // 是否开启批量任务功能 static const int CGRAPH_MAX_LOCAL_BATCH_SIZE = 2; // 批量执行本地任务最大值 static const int CGRAPH_MAX_POOL_BATCH_SIZE = 2; // 批量执行通用任务最大值 static const int CGRAPH_MAX_STEAL_BATCH_SIZE = 2; // 批量盗取任务最大值 static const bool CGRAPH_FAIR_LOCK_ENABLE = false; // 是否开启公平锁(非必须场景不建议开启,开启后CGRAPH_BATCH_TASK_ENABLE无效) static const int CGRAPH_SECONDARY_THREAD_TTL = 10; // 辅助线程ttl,单位为s -static const bool CGRAPH_MONITOR_ENABLE = true; // 是否开启监控程序 +static const bool CGRAPH_MONITOR_ENABLE = true; // 是否开启监控程序(如果不开启,辅助线程策略将失效。建议开启) static const int CGRAPH_MONITOR_SPAN = 5; // 监控线程执行间隔,单位为s static const bool CGRAPH_BIND_CPU_ENABLE = false; // 是否开启绑定cpu模式(仅针对主线程) static const int CGRAPH_PRIMARY_THREAD_POLICY = CGRAPH_THREAD_SCHED_OTHER; // 主线程调度策略 diff --git a/src/UtilsCtrl/ThreadPool/UThreadPoolInclude.h b/src/UtilsCtrl/ThreadPool/UThreadPoolInclude.h index afc5429..e279dad 100644 --- a/src/UtilsCtrl/ThreadPool/UThreadPoolInclude.h +++ b/src/UtilsCtrl/ThreadPool/UThreadPoolInclude.h @@ -16,5 +16,6 @@ #include "Queue/UQueueInclude.h" #include "Task/UTaskInclude.h" #include "Thread/UThreadInclude.h" +#include "Lock/ULockInclude.h" #endif //CGRAPH_UTHREADPOOLINCLUDE_H diff --git a/src/UtilsCtrl/UAllocator.h b/src/UtilsCtrl/UAllocator.h index dc30ed0..7dbccf8 100644 --- a/src/UtilsCtrl/UAllocator.h +++ b/src/UtilsCtrl/UAllocator.h @@ -9,17 +9,13 @@ #ifndef CGRAPH_UALLOCATOR_H #define CGRAPH_UALLOCATOR_H -#ifdef _GENERATE_SESSION_ - #include -#endif #include +#include -#include "UMemory.h" +#include "../CBasic/CBasicInclude.h" CGRAPH_NAMESPACE_BEGIN -static std::mutex g_session_mtx; - /** * 仅用于生成CObject类型的类 */ @@ -31,7 +27,7 @@ public: * @return */ template::value, int> = 0> + c_enable_if_t::value, int> = 0> static T* safeMallocCObject() { T* ptr = nullptr; while (!ptr) { @@ -40,35 +36,33 @@ public: return ptr; } - /** - * 生成unique智能指针信息 + * 生成带参数的普通指针 * @tparam T + * @tparam Args + * @param args * @return */ - template::value, int> = 0> - static std::unique_ptr makeUniqueCObject() { - return CTP::make_unique(); + template::value, int> = 0> + static T* safeMallocTemplateCObject(Args... args) { + T* ptr = nullptr; + while (!ptr) { + ptr = new T(std::forward(args)...); + } + return ptr; } /** - * 生成唯一标识信息 + * 生成unique智能指针信息 + * @tparam T * @return */ - static std::string generateSession() { - #ifdef _GENERATE_SESSION_ - std::lock_guard lock{ g_session_mtx }; - uuid_t uuid; - char session[36] = {0}; // 36是特定值 - uuid_generate(uuid); - uuid_unparse(uuid, session); - - return session; - #else - return CGRAPH_EMPTY; // 非mac平台,暂时不支持自动生成session信息 - #endif + template::value, int> = 0> + static std::unique_ptr makeUniqueCObject() { + return c_make_unique(); } }; @@ -79,9 +73,6 @@ public: #define CGRAPH_MAKE_UNIQUE_COBJECT(Type) \ UAllocator::makeUniqueCObject(); \ -#define CGRAPH_GENERATE_SESSION \ - UAllocator::generateSession(); \ - CGRAPH_NAMESPACE_END #endif //CGRAPH_UALLOCATOR_H diff --git a/src/UtilsCtrl/UMemory.h b/src/UtilsCtrl/UMemory.h deleted file mode 100644 index 3f04de6..0000000 --- a/src/UtilsCtrl/UMemory.h +++ /dev/null @@ -1,54 +0,0 @@ -/*************************** -@Author: MirrorYuChen -@Contact: 2458006366@qq.com -@File: UMemory.h -@Time: 2022/10/11 01:43 上午 -@Desc: -***************************/ - -#ifndef CGRAPH_UMEMORY_H -#define CGRAPH_UMEMORY_H - -#include -#include - -#include "../CBasic/CBasicInclude.h" - -CGRAPH_NAMESPACE_BEGIN - -template -using enable_if_t = typename std::enable_if::type; - -template -struct MakeUniqueResult { - using scalar = std::unique_ptr; -}; - -template -struct MakeUniqueResult { - using array = std::unique_ptr; -}; - -template -struct MakeUniqueResult { - using invalid = void; -}; - -template -typename MakeUniqueResult::scalar make_unique( - Args &&... args) { - return std::unique_ptr(new T(std::forward(args)...)); -} - -template -typename MakeUniqueResult::array make_unique(size_t n) { - return std::unique_ptr(new typename std::remove_extent[n]()); -} - -template -typename MakeUniqueResult::invalid make_unique( - Args &&... /* args */) = delete; - -CGRAPH_NAMESPACE_END - -#endif // CGRAPH_UMEMORY_H diff --git a/src/UtilsCtrl/UtilsDefine.h b/src/UtilsCtrl/UtilsDefine.h index 0e2cec8..91f50c2 100644 --- a/src/UtilsCtrl/UtilsDefine.h +++ b/src/UtilsCtrl/UtilsDefine.h @@ -29,7 +29,7 @@ CGRAPH_NAMESPACE_BEGIN /* 判断传入的指针信息是否为空 */ #define CGRAPH_ASSERT_NOT_NULL(ptr) \ if (unlikely(nullptr == (ptr))) { \ - return CStatus("ptr is nullptr"); \ + return CStatus("input is nullptr"); \ } \ #define CGRAPH_ASSERT_NOT_NULL_RETURN_NULL(ptr) \ @@ -37,10 +37,16 @@ CGRAPH_NAMESPACE_BEGIN return nullptr; \ } \ +#define CGRAPH_ASSERT_NOT_NULL_THROW_ERROR(ptr) \ + if (unlikely(nullptr == (ptr))) { \ + CGRAPH_THROW_EXCEPTION("input is null") \ + } + + /* 判断函数流程是否可以继续 */ static std::mutex g_check_status_mtx; #define CGRAPH_FUNCTION_CHECK_STATUS \ - if (unlikely(!status.isOK())) { \ + if (unlikely(status.isErr())) { \ std::lock_guard lock{ g_check_status_mtx }; \ CGRAPH_ECHO("%s | %s | line = [%d], errorCode = [%d], errorInfo = [%s].", \ __FILE__, __FUNCTION__, __LINE__, status.getCode(), status.getInfo().c_str()); \ @@ -64,6 +70,10 @@ static std::mutex g_check_status_mtx; return nullptr; \ } \ +#define CGRAPH_CHECK_STATUS_RETURN_THIS_OR_NULL \ + return status.isOK() ? this : nullptr; \ + + #define CGRAPH_SLEEP_MILLISECOND(ms) \ std::this_thread::sleep_for(std::chrono::milliseconds(ms)); \ diff --git a/src/UtilsCtrl/UtilsFunction.h b/src/UtilsCtrl/UtilsFunction.h index 207dbdb..1b9b4b0 100644 --- a/src/UtilsCtrl/UtilsFunction.h +++ b/src/UtilsCtrl/UtilsFunction.h @@ -15,6 +15,8 @@ #include #include +#include "../CBasic/CBasicInclude.h" + CGRAPH_NAMESPACE_BEGIN /** diff --git a/src/UtilsCtrl/UtilsObject.h b/src/UtilsCtrl/UtilsObject.h index 61e8750..8195962 100644 --- a/src/UtilsCtrl/UtilsObject.h +++ b/src/UtilsCtrl/UtilsObject.h @@ -14,7 +14,6 @@ CGRAPH_NAMESPACE_BEGIN class UtilsObject : public CObject { - public: CStatus run() override { CGRAPH_NO_SUPPORT diff --git a/tutorial.cpp b/tutorial.cpp index 34abb29..4fbb794 100644 --- a/tutorial.cpp +++ b/tutorial.cpp @@ -123,7 +123,7 @@ void tutorial_threadpool_3(UThreadPoolPtr tp) { int main() { - auto pool = make_unique(); // 构造一个线程池类的智能指针 + std::unique_ptr pool(new UThreadPool()); // 构造一个线程池类的智能指针 CGRAPH_ECHO("======== tutorial_threadpool_1 begin. ========"); tutorial_threadpool_1(pool.get());