Role of thread pool:
1. Avoid the cost of creating and destroying threads when processing short-term tasks;
2. In a large number of concurrent tasks, system resources can be used more reasonably to cut peak and level Valley to ensure the stability of system operation;
It has the following advantages to build thread pool based on C++11 standard;
1. Task does not need to inherit interface
2. Support lambda expression
3. Support global function and static member function;
4. Use bind to support member functions;
//Thread pool class CThreadPool : public ThreadObject { public: using ThreadObject::ThreadObject; //Start default thread pool void Start(int nThreadNum = 1) { m_idlThrNum = nThreadNum < 1 ? 1 : nThreadNum; for (auto size = 0; size < nThreadNum; ++size) { //Number of initialization threads m_pThreadPool.emplace_back( [this] { // Worker functions while (!this->m_bStop) { std::function<void(void)> task; { // Get a task to be executed // unique_lock vs lock_ The advantage of guard is that it can unlock() and lock() at any time std::unique_lock<std::mutex> lock(m_mu); this->m_condPop.wait(lock, [this] { return this->m_bStop.load() || !this->m_taskQueue.empty(); } ); // wait until there is a task if (this->m_bStop && this->m_taskQueue.empty()) return; task = std::move(this->m_taskQueue.front()); // Take a task this->m_taskQueue.pop(); } //Notification writer thread m_condPush.notify_one(); m_idlThrNum--; task(); m_idlThrNum++; } } ); } } //Submit task to thread pool template<class F, class... Args> auto Commit(F&& f, Args&&... args) -> std::future<decltype(f(args...))> { using return_type = decltype(f(args...)); auto task = std::make_shared< std::packaged_task<return_type()> >( std::bind(std::forward<F>(f), std::forward<Args>(args)...) ); std::future<return_type> res = 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 jobs to a stopped thread pool"); while (m_taskQueue.size() == m_nCapacity) //Queue full { m_condPush.wait(m_mu); //Wait, will unlock temporarily } m_taskQueue.emplace([task]() { (*task)(); }); } m_condPop.notify_one(); return res; } virtual size_t GetTaskNum() { return m_taskQueue.size(); } private: std::queue<std::function<void()>> m_taskQueue; //queue };
Test code:
void Func1(int i, const std::string& msg) { std::cout << i << "-->" << msg<< std::endl; } int Func2(int i, const std::string& msg) { std::cout << i << "-->" << msg << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(1000)); return i * 100; } class PrintTest { public: void Func1(int i, const std::string& msg) { std::cout << i << "-->" << msg << std::endl; } void Func2(int i) { std::cout << i << "-->" << "Test member functions" << std::endl; } }; int main() { CThreadPool pool; pool.Start(2); //Test lambda expressions pool.Commit([] ); //Test lambda expression with parameters pool.Commit([](int val), 999); //Test global functions pool.Commit(Func1, 100, "Test global functions"); //Test member functions PrintTest p; pool.Commit(std::mem_fn(&PrintTest::Func1),&p , 200, "Test member functions"); //Test synchronization get results auto res = pool.Commit(Func2, 300, "Test synchronization get results"); auto val = res.get(); std::cout << "Get results:" << val << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(5000)); return 0; }