多线程之手撕生产者-消费者

某糕 / 2024-09-24 / 原文

要点

  • 维护一个资源(在生产者-消费者中即流水线的位置)池,实现put()/get()两个函数。由于对信号量的操作是互斥的,要引入条件变量和信号量。
  • 实现资源池类Pool,成员变量:
    • mtx : mutex
    • cv : condition_variable
    • que : queue
    • capacity : int
  • 实现资源池类Pool,成员函数:
    • T get() : 获取一个队列头的资源
    • void put(T val) : 放置一个资源到队列末尾

代码实现

  #include <iostream>
  #include <thread>
  #include <mutex>
  #include <queue>
  using namespace std;

  template<typename T>
  class Pool {
  private:
  	int capacity;
  	mutex mtx;
  	condition_variable cv;
  	queue<T> que;
  public:
  	Pool(int _capacity) : capacity(_capacity) {}

  	void put(T pdt) {
  		unique_lock<mutex> ulock(mtx);
  		while (que.size() >= capacity) {
  			cv.wait(ulock);
  		}
  		que.push(pdt);
  		cv.notify_all();
  		cout << "生产了商品 " << pdt << endl;
  		return;
  	}

  	T get() {
  		unique_lock<mutex> ulock(mtx);
  		while (que.empty()) {
  			cv.wait(ulock);
  		}
  		int pdt = que.front();
  		que.pop();
  		cv.notify_all();
  		cout << "消费了商品 " << pdt << endl;
  		return pdt;
  	}
  };

  int main() {
  	Pool<int> pool(3);

  	thread t1([&pool]() {
  		for (int i = 0; i < 10; ++i) {
  			pool.put(i);
  			this_thread::sleep_for(chrono::milliseconds(200));
  		}
  		return;
  	});

  	thread t2([&pool]() {
  		for (int i = 0; i < 10; ++i) {
  			pool.get();
  			this_thread::sleep_for(chrono::milliseconds(300));
  		}
  		return;
  	});

  	t1.join();
  	t2.join();

  	return 0;
  }