【C++11】c++11實現執行緒池

徘徊彼岸花發表於2024-05-05
#include <iostream> 
#include <mutex>
#include <queue>
#include <vector>
#include <functional>
#include <condition_variable>
#include <atomic>
#include <chrono>

class ThreadPool
{
public:
	ThreadPool(int num)
	{
		stopAll = false;	//執行緒池物件停止標誌
		m_numThreads = num < 1 ? 1 : num;	//最少1個執行緒
		
		for (int i = 0; i < m_numThreads; i++)
		{
			m_threads.emplace_back([=]() {	//emplace_back移動語義,不複製
				while (true)	
				{
					std::unique_lock<std::mutex> ul(mtx);	//互斥鎖,鎖住對共享變數m_tasks的訪問
					cv.wait(ul, [=]() {						//條件變數控制鎖ul的釋放、執行緒的阻塞和繼續
						return !m_tasks.empty() || stopAll;	//任務佇列非空或執行緒池停止則不阻塞,拿到ul
						});
					if (stopAll == true && m_tasks.empty())	//如果執行緒池停止執行緒立即return終止
					{
						return;
					}
					std::function<void()> task(std::move(m_tasks.front()));	//從頭部取任務,移動語義減少複製,可呼叫物件包裝器包裝
					m_tasks.pop();	//任務佇列彈出
					ul.unlock();	//任務佇列訪問結束,解鎖放掉ul
					
					std::cout << "threadID=" << std::this_thread::get_id() << ",start working..." << std::endl;	
					task();	//執行緒執行任務
					std::cout << "threadID=" << std::this_thread::get_id() << ",end working..." << std::endl;	//執行緒執行完任務日誌輸出
				}
				});
		}
	}
	ThreadPool(ThreadPool& another) = delete;	//禁用複製
	ThreadPool& operator=(ThreadPool& another) = delete;	//禁用operator=
	~ThreadPool()
	{
		//析構銷燬執行緒池,釋放資源
		std::unique_lock<std::mutex> ul(mtx);	//要訪問共享變數stopAll(多個執行緒都訪問了stopAll),上鎖
		stopAll = true;	//執行緒池停止標誌置true
		ul.unlock();	//stopAll訪問結束,解鎖
		cv.notify_all();	//執行緒池要銷燬了。通知所有執行緒全部不阻塞向下執行
		for (auto& item : m_threads)
		{
			item.join();	//等待全部執行緒return終止
		}
	}

	//主執行緒新增任務。生產者
	template<typename F, typename... Args>
	void enqueue(F&& f, Args&&... args)	//萬能引用
	{
		auto task = std::bind(std::forward<F>(f), std::forward<Args>(args)...);	//f和args是萬能引用需要完美轉發,透過bind把引數繫結到函式f上
		//區域性作用域,限定互斥鎖ul鎖定範圍
		{
			std::unique_lock<std::mutex> ul(mtx);	//要訪問共享變數m_tasks,上鎖
			m_tasks.emplace(std::move(task));		//任務佇列裡放1個任務,移動語義避免複製
		}
		cv.notify_one();	//放了個任務,解除1個執行緒的阻塞向下執行任務
	}

private:
	std::mutex mtx;	//互斥量
	std::condition_variable cv;	//條件變數
	bool stopAll;
	int m_numThreads;	//執行緒數
	std::queue<std::function<void()>> m_tasks;	//任務佇列。bind繫結了引數,所以function的模版型別是void()
	std::vector<std::thread> m_threads;	//執行緒容器
};


std::mutex mtxfunc;
int data;
void func()
{
	std::unique_lock<std::mutex> ul(mtxfunc);
	for (int i = 0; i < 1000000; i++)
	{
		data++;
	}
}

int main()
{
	auto start1 = std::chrono::steady_clock::now();
	ThreadPool* tp = new ThreadPool(6);
	tp->enqueue(func);
	tp->enqueue(func);
	tp->enqueue(func);
	tp->enqueue(func);
	tp->enqueue(func);
	tp->enqueue(func);
	auto end1 = std::chrono::steady_clock::now();
	delete tp;
	std::cout << "MainThreadID=" << std::this_thread::get_id() << ", final data= " << data << std::endl;

	auto start2 = std::chrono::steady_clock::now();
	std::cout << "pool spend:" << std::chrono::duration_cast<std::chrono::microseconds>(end1 - start1).count() << "ms" << std::endl;
	for (int i = 0; i < 6000000; i++)
	{
		data++;
	}
	auto end2 = std::chrono::steady_clock::now();
	std::cout << "mainthread spend:" << std::chrono::duration_cast<std::chrono::microseconds>(end2 - start2).count() << "ms" << std::endl;

}

相關文章