多執行緒之手撕執行緒池

某糕發表於2024-09-24

要點

  • 執行緒池,功能是管理執行緒資源,管理任務佇列。空閒執行緒從任務佇列中取出任務完成,需要執行緒時將任務掛在任務對列。
  • 由於對任務佇列的操作要實現同步,引入了互斥訊號量和條件變數。
  • 當執行緒池生命週期結束時,不允許再掛載任務,引入一個原子變數stop_flag
  • 實現執行緒池ThreadPool類,成員變數有:
    • vector : workers
    • queue<function<void()>> : tasks
    • mtx : mutex
    • cv :conditon_vatiable
    • stop_flag : atomic
  • 實現執行緒池ThreadPool類,成員函式有:
    • ThreadPool(int size) : 開闢大小為size的執行緒池,建立size個執行緒worker存在workers裡,安排worker從tasks中取出任務執行
    • void puts(Function<void()>&& F) : 把任務f掛在任務佇列tasks下
    • ~ThreadPool() : stop並join結束所有執行緒

程式碼實現

  #include <iostream>
  #include <vector>
  #include <queue>
  #include <thread>
  #include <memory>
  #include <mutex>
  #include <atomic>
  #include <functional>
  using namespace std;

  class ThreadPool {
  private:
  	vector<thread> workers;
  	queue<function<void()>> tasks;
  	mutex mtx_for_que;
  	condition_variable cv;
  	atomic<bool> stop_flag;
  public:
  	ThreadPool(int size);
  	void make_Task(function<void()>&& f);
  	~ThreadPool();
  };

  ThreadPool::ThreadPool(int size) : stop_flag(false) {
  	for (int i = 0; i < size; ++i) {
  		workers.emplace_back([this]() {
  			for (;;) {
  				unique_lock<mutex> ulock(this->mtx_for_que);
  				while (!this->stop_flag && this->tasks.empty()) {
  					this->cv.wait(ulock);
  				}
  				if (this->stop_flag && this->tasks.empty()) {
  					return;
  				}
  				function<void()> task = move(this->tasks.front());
  				this->tasks.pop();

  				// 執行
  				task();
  			}
  		});
  	}
  }

  void ThreadPool::make_Task(function<void()>&& f) {
  	function<void()> task = f;
  	
  	unique_lock<mutex> ulock(mtx_for_que);
  	if (stop_flag) {
  		cout << "This ThreadPool has been stopped!" << endl;
  		return;
  	}
  	tasks.emplace([task]() {(task)(); });
  	cv.notify_one();
  	return;
  }

  ThreadPool::~ThreadPool() {
  	stop_flag = true;
  	cv.notify_all();
  	for (auto& worker : workers) {
  		worker.join();
  	}
  	return;
  }

  int main() {
  	ThreadPool pool(4);
  	for (int i = 0; i < 20; ++i) {
  		pool.make_Task([i]() {
  			cout << i << endl;
  		});
  	}
  	return 0;
  }

相關文章