C++訊息佇列
阿新 • • 發佈:2018-12-25
在編寫多執行緒程式的時候常用到一種模型叫做 one-loop-per-thread,就是每個執行緒一個迴圈來處理邏輯,這就需要一個訊息佇列來支援執行緒間訊息的投遞。封裝好的執行緒模型只需要在訊息進出和訪問公共資料的時候進行加鎖保護,其他情況下不需要加鎖,從而最大程度的較少鎖的碰撞,這也是one-loop-per-thread的優點之一。
這裡我通過C++11的互斥量和條件變數實現了一個訊息佇列。先把原始碼貼上:
#ifndef HEADER_TASKQUEUE
#define HEADER_TASKQUEUE
#include <list>
#include <mutex>
#include <condition_variable>
template<typename T>
class CTaskQueue {
public:
CTaskQueue(int size = -1) :_list_size(size > 0 ? size : INT_MAX) {
}
~CTaskQueue() {
}
void Push(const T& element) {
std::unique_lock<std::mutex> lock(_block_mutex);
_full_notify.wait(_block_mutex, [this ]() {return this->_block_queue.size() < this->_list_size; });
_block_queue.push_front(element);
_empty_notify.notify_all();
}
T Pop() {
std::unique_lock<std::mutex> lock(_block_mutex);
_empty_notify.wait(_block_mutex, [this]() {return !this->_block_queue.empty(); });
T ret = std ::move(_block_queue.back());
_block_queue.pop_back();
_full_notify.notify_all();
return std::move(ret);
}
void Clear(bool notify = true) {
std::unique_lock<std::mutex> lock(_block_mutex);
while (!_block_queue.empty()) {
_block_queue.pop_front();
_full_notify.notify_one();
}
}
int Size() {
std::unique_lock<std::mutex> lock(_block_mutex);
return _block_queue.size();
}
private:
int _list_size;
std::list<T> _block_queue;
std::mutex _block_mutex;
std::condition_variable_any _empty_notify;
std::condition_variable_any _full_notify;
};
#endif
C++11引入了互斥量和條件變數來支援多執行緒程式設計,std::unique_lock lock(_block_mutex) 是RAII的常用伎倆,如果獲取不到鎖的話會阻塞到這裡。condition_variable_any 條件變數也會去競爭鎖,但條件不滿足時會釋放鎖並阻塞程序,直到其他執行緒呼叫notify系列函式來喚醒。我們僅僅用到兩個多執行緒程式設計的工具便可實現一個高效的訊息佇列,在《mudo多執行緒程式設計》中,陳碩說這兩個工具在多數情況下都能滿足多執行緒程式設計的效能需求,而不用去用複雜的讀寫鎖和其他可重入的鎖。不可不讀書也不可盡信書,站在前人的肩膀上還是有收穫的。
GitHub:https://github.com/caozhiyi/Base