对C++中的队列进行多线程访问

Multi-threaded access to a Queue in C++

本文关键字:多线程 访问 队列 C++      更新时间:2023-10-16

所以基本上我有两个线程:一个生成字符串的组合并将它们附加到作为类成员的队列中。 第二个线程应该将该队列中的所有内容打印到文件中。如果队列为空,我应该等到有另一个元素,依此类推。

std::mutex m;
Class c{
std::queue<std::string> q;
std::ofstream file;
void print(std::string str){
file << str << "n";
} // Print to file
void generate(){
str = "abc" // do stuff
q.push(str);
}
}

当我使用std::mutex程序的性能变得非常糟糕时。 我想我需要一个管理对队列的访问的函数,以便我可以同时写入和打印。我该怎么做?

void Generator::print() {
int c = 0;
while (c < totalN){
if(!printQueue.empty()){
fileStream << printQueue.front() << 'n';
printQueue.pop();
c++;
}
}
}
void Generator::getCombinations(unsigned long start, unsigned long end) {
// Fill with dummy elements
std::string comb(length, ' ');
std::string temp(length, ' ');
auto total_n = static_cast<unsigned long>(std::pow(elementCount, length));
for (auto i = start; i < end; ++i) {
auto n = i;
for (size_t j = 0; j < length; ++j) {
comb[comb.size() - j - 1] = charPool[n % elementCount];
n /= elementCount;
}
temp = comb;
for (auto f : tasks) (this->*f)(temp); // Call addQueue func
}
}

void Generator::addToQueue(std::string &str) {
m.lock();
printQueue.push(str);
m.unlock();
}

出于某种原因,我收到错误的访问错误,因为 prints 函数尝试从空队列中打印某些内容,这对我来说似乎是不可能的,因为这部分代码仅在队列不为空时才执行......

Generator::Print函数中,最好将共享队列换成空队列,然后使用内容:

void Generator::print() {
int todo = totalN;
while (todo) {
std::this_thread::sleep_for(500ms);
std::queue<std::string> temp;
{ // Lock only taken for this section
std::lock_guard<std::mutex> lock(m);
std::swap(temp, q);
}
todo -= temp.size();
while (!temp.empty()) {
fileStream << temp.front() << 'n';
temp.pop();
}
}
}

这最多每 500 毫秒锁定一次,并且仅足够长的时间将q替换为temp。然后它可以按照自己的节奏打印内容。

请注意,如果生成比打印慢得多,您可以一次弹出一个,而不是像我在这里所做的那样交换队列。

这是一个称为生产者/消费者队列的标准问题。
C++ 中,当前开箱即用的解决方案是 condition_variable。如果您点击该链接,您将找到一个示例解决方案。注意您缺少的一些功能

  • 始终通过标准::lock_guard或标准::unique_lock锁定/解锁。
  • 如果速度很重要,请使用条件变量来控制每个线程唤醒或睡眠的时间。
  • 对结构的每个访问都必须同步。这包括推送/弹出,甚至包括调用清空等常量函数。

给定你的代码在哪里,并且考虑到问题是众所周知的。我建议你应该开始寻找现有的代码。从扫描中读取,这看起来像一个合理的概述。特别是,查看"有界缓冲区"部分。
Boost有一些不使用互斥锁的实现。这比您似乎需要的更先进。我不会为你建议这个,但其他人可能会觉得这很有趣。 https://www.boost.org/doc/libs/1_54_0/doc/html/boost/lockfree/queue.html