阻塞隊列就是多線程線程安全的隊列,在多線程場景下經常用到,c++ 標準庫裏面沒有提供阻塞隊列,boost 中有提供,生成環境下可以使用
blocking queue 實現
主要設計思路:
- 使用
std::vector
實現一個環形隊列,使用兩個指針 start 和 end 來標識起止位置,push 的時候在 end 處插入,pop 的時候直接 start 指針往後移即可 - 使用
std::condition_variable
實現同步,push 的時候需要滿足_not_full
條件,push 完成發送_not_empty
通知,pop 的時候需要滿足_not_empty
條件,pop 完成發送_not_full
通知
template <typename T>
class BlockingQueue {
std::mutex _mutex;
std::condition_variable _not_full;
std::condition_variable _not_empty;
int _start;
int _end;
int _capacity;
std::vector<T> _vt;
public:
BlockingQueue(const BlockingQueue<T>& other) = delete;
BlockingQueue<T>& operator=(const BlockingQueue<T>& other) = delete;
BlockingQueue(int capacity) : _capacity(capacity), _vt(capacity + 1), _start(0), _end(0) {}
bool isempty() {
return _end == _start;
}
bool isfull() {
return (_start + _capacity - _end) % (_capacity + 1) == 0;
}
void push(const T& e) {
std::unique_lock<std::mutex> lock(_mutex);
while (isfull()) {
_not_full.wait(lock);
}
_vt[_end++] = e;
_end %= (_capacity + 1);
_not_empty.notify_one();
}
T pop() {
std::unique_lock<std::mutex> lock(_mutex);
while (isempty()) {
_not_empty.wait(lock);
}
auto res = _vt[_start++];
_start %= (_capacity + 1);
_not_full.notify_one();
return res;
}
};
生成者消費者
生成者線程不斷往隊列面插入一個隨機數,消費者線程從隊列裏面取
void producer(BlockingQueue<int>& q, int i) {
while (true) {
std::random_device rd;
auto p = rd() % 10;
q.push(p);
std::cout << "produce " << i << " [" << p << "]" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1500 + rd() % 5000));
}
}
void consumer(BlockingQueue<int>& q, int i) {
while (true) {
std::random_device rd;
auto p = q.pop();
std::cout << "consume " << i << " [" << p << "]" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1500 + rd() % 5000));
}
}
void producerConsumer() {
BlockingQueue<int> q(4);
std::vector<std::thread> ps(10);
std::vector<std::thread> cs(20);
for (int i = 0; i < ps.size(); i++) {
ps[i] = std::thread(producer, std::ref(q), i);
}
for (int i = 0; i < cs.size(); i++) {
cs[i] = std::thread(consumer, std::ref(q), i);
}
for (int i = 0; i < ps.size(); i++) {
ps[i].join();
}
for (int i = 0; i < ps.size(); i++) {
cs[i].join();
}
}
鏈接
轉載請註明出處
本文鏈接:https://tech.hatlonely.com/article/60