[英]CountDownLatch in C++ using Boost Mutexes and Condition
[英]C++ - Condition Variable without Mutexes?
我想我誤解了 CV-Mutex 設計模式,因為我正在創建一個似乎不需要互斥鎖的程序,只需要 CV。 如果有人可以幫助解釋我在這里做錯了什么,我很樂意學習。
我正在解析來自 2 個不同帳戶的網站的提要。 Alice
, Bob
。 解析任務很慢,所以我有兩個單獨的線程,每個線程都專用於處理來自Alice
和Bob
的提要。
然后,我有一個線程從網絡接收消息並將工作分配給threadA
或threadB
,具體取決於更新消息的對象。 這樣,閱讀器/網絡線程就不會停止, Alice
的消息是有序的, Bob
的消息也是有序的。
我不在乎Alice
線程是否按時間順序落后於Bob
線程,只要各個帳戶提要按順序排列即可。
這與線程池非常相似,不同之處在於線程基本上被鎖定到大小為 2 的固定大小數組,並且我對每個提要使用相同的線程。
我創建了一個AccountThread
class,它維護一個 JSON 消息queue
,以便在 class 中盡快處理。 這是代碼:
#include <queue>
#include <string>
#include <condition_variable>
#include <mutex>
using namespace std;
class AccountThread {
public:
AccountThread(const string& name) : name(name) { }
void add_message(const string& d) {
this->message_queue.push(d);
this->cv.notify_all(); // could also do notify_one but whatever
}
void run_parsing_loop() {
while (true) {
std::unique_lock<std::mutex> mlock(lock_mutex);
cv.wait(mlock, [&] {
return this->is_dead || this->message_queue.size() > 0;
});
if (this->is_dead) { break; }
const auto message = this->message_queue.front();
this->message_queue.pop();
// Do message parsing...
}
}
void kill_thread() {
this->is_dead = true;
}
private:
const string& name;
condition_variable cv;
mutex lock_mutex;
queue<string> message_queue;
// To Kill Thread if Needed
bool is_dead;
};
我可以添加 main.cpp 代碼,但它本質上只是一個讀取器循環,它根據帳戶名稱調用thread.add_message(message)
。
為什么我在這里需要lock_mutex
? 我看不出它的目的,因為這個 class 本質上是單線程的。 有沒有更好的設計模式呢? 我覺得如果我包含了一個我並不真正需要的變量,比如mutex
,那么我在這個任務中使用了錯誤的設計模式。
我只是在修改我在網上看到的關於線程池實現的一些文章中的代碼,並且很好奇......感謝任何幫助。 謝謝!
首先要做的事情是:沒有互斥鎖就沒有condition_variable::wait
。 wait
的接口需要互斥量。 所以關於
我正在創建一個似乎不需要互斥鎖的程序,只需要 CV
請注意,需要互斥鎖來保護條件變量本身。 如果在沒有互斥鎖的情況下如何進行數據競爭的概念沒有立即意義,請檢查為什么 pthreads 的條件變量函數需要互斥鎖。
其次,您提供的代碼中有多個痛點。 考慮解決問題的這個版本,我將在下面解釋問題:
class AccountThread {
public:
AccountThread(const string& name) : name(name)
{
consumer = std::thread(&AccountThread::run_parsing_loop, this); // 1
}
~AccountThread()
{
kill_thread(); // 2
consumer.join();
}
void add_message(const string& d) {
{
std::lock_guard lok(lock_mutex); // 3
this->message_queue.push(d);
}
this->cv.notify_one();
}
private:
void run_parsing_loop()
{
while (!is_dead) {
std::unique_lock<std::mutex> mlock(lock_mutex);
cv.wait(mlock, [this] { // 4
return is_dead || !message_queue.empty();
});
if (this->is_dead) { break; }
std::string message = this->message_queue.front();
this->message_queue.pop();
string parsingMsg = name + " is processing " + message + "\n";
std::cout << parsingMsg;
}
}
void kill_thread() {
{
std::lock_guard lock(lock_mutex);
this->is_dead = true;
}
cv.notify_one(); // 5
}
private:
string name; // 6
mutable condition_variable cv; // 7
mutable mutex lock_mutex;
std::thread consumer;
queue<string> message_queue;
bool is_dead{false}; // 8
};
從上到下指出的問題(在編號的評論中是):
AccountThread
,那么當 class 提供線程時,更容易正確處理。 這樣,只有相關的接口被暴露,你可以更好地控制消費者的生命周期和工作。AccountThread
“死亡”時,工人也應該死亡。 在上面的示例中,我通過終止析構函數中的消費者線程來修復此依賴關系。add_message
在您的代碼中導致了數據競爭。 由於您打算在不同的線程中運行解析循環,因此在沒有關鍵部分的情況下簡單地推送到隊列是錯誤的。this
捕獲它會更干凈,例如,您可能不需要對捕獲的mlock
的引用。kill_thread
不正確。 您需要通知可能正在等待的消費者線程 state 發生了變化。 要正確執行此操作,您需要使用鎖保護在謂詞中簽入的 state。const string &name
的初始版本可能不是您想要的。 成員 const 引用不會延長臨時對象的生命周期,並且構造函數的編寫方式可能會使實例帶有懸空的 state。 即使您進行典型檢查,使用 r 值參考版本重載構造函數,您也將依賴於比您的AccountThread
object 存活時間更長的外部字符串。 更好地使用價值成員。is_alive
成員在未初始化的情況下被使用。總而言之,我認為建議的改變指向了正確的方向。 如果您想更深入地了解您提到的 TBB 組件之類的實現方式,還可以檢查類似 Go 的通信渠道的實現。 這樣的通道(或緩沖區隊列)將簡化實現以避免手動使用互斥鎖、CV 和活動狀態:
class AccountThread {
public:
AccountThread(const string& name) : name(name) {
consumer = std::thread(&AccountThread::run_parsing_loop, this);
}
~AccountThread() {
kill_thread();
consumer.join();
}
void add_message(const string& d) { _data.push(d); }
private:
void run_parsing_loop() {
try {
while (true) {
// This pop waits until there's data or the channel is closed.
auto message = _data.pop();
// TODO: Implement parsing here
}
} catch (...) {
// Single exception thrown per thread lifetime
}
}
void kill_thread() { _data.set(yap::BufferBehavior::Closed); }
private:
string name;
std::thread consumer;
yap::BufferQueue<string> _data;
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.