Thread factory of the nine Yin scriptures of C + +

The first part mainly introduces the use scenario of thread factory, and this part mainly introduces the implementation ...

The first part mainly introduces the use scenario of thread factory, and this part mainly introduces the implementation of thread factory.

The thread factory consists of two parts:

First, factory class, which is mainly responsible for creating thread class and receiving and extracting data;

Second, it is the thread interface class, which mainly defines the thread entry class and the public interface to receive messages;

According to the message model, it can be divided into data-based factory class and task-based factory class.

Factory class definition:

class CThreadFactoryBase { public: virtual ~CThreadFactoryBase() {}; virtual bool IsStop() = 0; virtual bool Pop(AnyVar& val, int waitTime = -1) = 0; }; //task model struct TaskModel {}; //data model struct DataModel {}; template<typename T, typename P> class __ThreadFactory;

Task model factory class implementation

template<typename T> class __ThreadFactory<T, typename std::enable_if<std::is_same<typename T::ModelType, TaskModel>::value, TaskModel>::type> : public ThreadObject, public CThreadFactoryBase { using ValType = typename T::ValueType; using ValuePtrType = typename T::ValuePtrType; using RetType = typename T::RetType; using RecvType = typename T::RecvType; public: //Pressing a task into a queue auto Push(typename T::RecvType val) ->std::future<RetType> { ValuePtrType task = std::make_shared<ValType>(val); std::future<RetType> future = task->get_future(); { std::unique_lock<std::mutex> lock(m_mu); //Submitting jobs to a stopped thread pool is not allowed if (m_bStop) throw std::runtime_error("Submit a job to a stopped thread factory"); while (m_taskQueue.size() == m_nCapacity) //Queue full { m_condPush.wait(m_mu); //Wait, will unlock temporarily } m_taskQueue.push(task); } m_condPop.notify_one(); // Wake up a thread to execute return future; } protected: std::queue<ValuePtrType> m_taskQueue; //queue };

Data model factory class implementation

template <typename T, typename RET> struct DataNode { T data; std::promise<RET> res; DataNode(const T& d, std::promise<RET>& prs) :data(d), res(std::move(prs)) {} }; template<typename T> class __ThreadFactory<T, typename std::enable_if<std::is_same<typename T::ModelType, DataModel>::value, DataModel>::type> : public ThreadObject, public CThreadFactoryBase { using ValType = typename T::ValueType; using ValuePtrType = typename T::ValuePtrType; using RetType = typename T::RetType; using RecvType = typename T::RecvType; public: //Pressing a task into a queue std::future<RetType> Push(const RecvType& val) { std::promise<RetType> prs; auto future = prs.get_future(); ValuePtrType tupVal = std::make_shared<ValType>( val, prs ); { std::unique_lock<std::mutex> lock(m_mu); //Submitting jobs to a stopped thread pool is not allowed if (m_bStop) throw std::runtime_error("Submit a job to a stopped thread factory"); while (m_taskQueue.size() == m_nCapacity) //Queue full { m_condPush.wait(m_mu); //Wait, will unlock temporarily } m_taskQueue.push(tupVal); } m_condPop.notify_one(); // Wake up a thread to execute return future; } protected: std::queue<ValuePtrType> m_taskQueue; //queue };

Factory class implementation, according to the thread interface class model, automatic identification

template<typename T> class CThreadFactory: public __ThreadFactory<T, typename T::ModelType> { public: ~CThreadFactory() { Stop(); for (std::thread& thread : m_pThreadPool) { if (thread.joinable()) thread.join(); // Wait for the task to finish, provided that the thread will finish executing } m_pThreadPool.clear(); } template<typename ...P> void Start(unsigned short nThreadNum = 1, P&&... p) { for (size_t i = 0; i < nThreadNum; i++) { m_pThreadPool.emplace_back([this, p...]() { T obj(*this, p...); obj.Run(); }); } } //Get a task from the task queue //waitTime: is the waiting time in seconds bool Pop(AnyVar& task, int waitTime = -1) { m_idlThrNum++; { std::unique_lock<std::mutex> lock(m_mu); if (waitTime < 0) { this->m_condPop.wait(lock, [this] { return this->m_bStop.load() || !this->m_taskQueue.empty(); }); // wait until there is a task } else { auto status = m_condPop.wait_for(lock, std::chrono::seconds(waitTime), [this] { return this->m_bStop.load() || !this->m_taskQueue.empty(); }); if (!status) { m_idlThrNum--; return false; } } if (this->m_taskQueue.empty()) { if (this->m_bStop) { m_idlThrNum--; } return false; } task = std::move(this->m_taskQueue.front()); // Take a task this->m_taskQueue.pop(); } //Notification writer thread m_condPush.notify_one(); m_idlThrNum--; return true; } virtual size_t GetTaskNum() { return m_taskQueue.size(); } virtual bool IsStop() { return ThreadObject::IsStop(); } };

Thread interface class implementation

//Task based thread interface template<typename RET, typename... Args> class BaseOnTask { public: using ModelType = TaskModel; using ValueType = std::packaged_task<RET(Args ...)>; using ValuePtrType = std::shared_ptr<std::packaged_task<RET(Args ...)>>; using RecvType = std::function<RET(Args ...)>; using RetType = RET; }; template<typename RET, typename... Args> class BaseOnData { public: using ModelType = DataModel; using ValueType = DataNode<std::tuple<Args ...>, RET>; using ValuePtrType = std::shared_ptr<DataNode<std::tuple<Args ...>, RET>>; using RecvType = std::tuple<Args...>; using RetType = RET; }; //Task thread interface template<typename T> class ThreadJob : public T { public: using ValType = typename T::ValueType; using ValuePtrType = typename T::ValuePtrType; using RetType = typename T::RetType; using ModelType = typename T::ModelType; using RecvType = typename T::RecvType; ThreadJob(CThreadFactoryBase& factory) :m_factory(factory) {} bool GetJob(ValuePtrType& task, int waitTime = -1) { AnyVar val; if (m_factory.Pop(val, waitTime)) { task = any_cast<ValuePtrType>(val); return true; } return false; } bool IsStop() { return m_factory.IsStop(); } //Thread start function virtual void Run() = 0; private: CThreadFactoryBase& m_factory; }; template<typename RET, typename... Args> class BaseTaskThread : public ThreadJob< BaseOnTask<RET, Args...>> { public: using ThreadJob< BaseOnTask<RET, Args...>>::ThreadJob; }; template<typename RET, typename... Args> class BaseDataThread : public ThreadJob< BaseOnData<RET, Args...>> { public: using ThreadJob< BaseOnData<RET, Args...>>::ThreadJob; };

3 June 2020, 12:04 | Views: 3114

Add new comment

For adding a comment, please log in
or create account

0 comments