【发布时间】:2023-03-17 08:13:01
【问题描述】:
除了主线程,我还有一个线程接收数据并将它们写入文件。
std::queue<std::vector<int>> dataQueue;
std::mutex mutex;
void setData(const std::vector<int>& data) {
std::lock_guard<std::mutex> lock(mutex);
dataQueue.push(data);
}
void write(const std::string& fileName) {
std::unique_ptr<std::ostream> ofs = std::unique_ptr<std::ostream>(new zstr::ofstream(fileName));
while (store) {
std::lock_guard<std::mutex> lock(mutex);
while (!dataQueue.empty()) {
std::vector<int>& data= dataQueue.front();
ofs->write(reinterpret_cast<char*>(data.data()), sizeof(data[0])*data.size());
dataQueue.pop();
}
}
}
}
setData 被主线程使用,write 实际上是写线程。我使用std::lock_quard 来避免内存冲突,但是当锁定写入线程时,它会减慢主线程,因为它必须等待队列被解锁。但我想我可以避免这种情况,因为线程永远不会同时作用于队列的同一个元素。
所以我想做到无锁,但我真的不明白我应该如何实现它。我的意思是,我怎么能在不锁定任何东西的情况下做到这一点?此外,如果写入线程比主线程快,则队列可能大部分时间都是空的,因此它应该以某种方式等待新数据,而不是无限循环以检查非空队列。
编辑:我将简单的std::lock_guard 更改为std::cond_variable,以便它可以在队列为空时等待。但是主线程仍然可以被阻塞,当cvQeue.wait(.)被解析时,它会重新获得锁。另外,如果主线程执行cvQueue.notify_one(),而写线程没有等待呢?
std::queue<std::vector<int>> dataQueue;
std::mutex mutex;
std::condition_variable cvQueue;
void setData(const std::vector<int>& data) {
std::unique_lock<std::mutex> lock(mutex);
dataQueue.push(data);
cvQueue.notify_one();
}
void write(const std::string& fileName) {
std::unique_ptr<std::ostream> ofs = std::unique_ptr<std::ostream>(new zstr::ofstream(fileName));
while (store) {
std::lock_guard<std::mutex> lock(mutex);
while (!dataQueue.empty()) {
std::unique_lock<std::mutex> lock(mutex);
cvQueue.wait(lock);
ofs->write(reinterpret_cast<char*>(data.data()), sizeof(data[0])*data.size());
dataQueue.pop();
}
}
}
}
【问题讨论】:
-
您可以简单地在
write呼叫周围解锁,然后重新锁定。写入时无需持有锁,这可能是循环中最耗时的部分。
标签: multithreading c++11 locking lock-free