C++中对队列的多线程访问
Posted
技术标签:
【中文标题】C++中对队列的多线程访问【英文标题】:Multi-threaded access to a Queue in C++ 【发布时间】:2019-12-23 11:12:27 【问题描述】:所以基本上我有两个线程:一个生成字符串的组合并将它们附加到作为类成员的队列中。 第二个线程应该将该队列中的所有内容打印到文件中。如果队列是空的,我应该等到有另一个元素等等。
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 函数试图从空队列中打印一些东西,这对我来说似乎是不可能的,因为这部分代码仅在队列不为空时才执行...
【问题讨论】:
请展示您实际使用互斥锁的代码和您的两个线程。每个线程在持有互斥锁时做了多少工作? 互斥锁被锁定时你在做什么?您何时何地锁定它?你如何使用这个类和它包含的队列?请尝试创建minimal reproducible example 向我们展示,否则将很难为您提供帮助。也请刷新how to ask good questions,以及this question checklist。 添加了更多代码 您似乎只保护了对addToQueue
内部队列的访问,该队列不提供任何同步,因此由于竞争条件您获得了 UB。
但是我有一个全局互斥变量
【参考方案1】:
在您的 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
。然后它可以按照自己的节奏打印内容。
请注意,如果生成比打印慢得多,您可以一次弹出一个,而不是像我在这里那样交换队列。
【讨论】:
for 循环对我不起作用。我认为您不能以这种方式遍历队列.. 你是对的。我编辑了我的答案以使用front
和 pop
而不是 for-each 循环。
谢谢!那为我完成了工作! +1【参考方案2】:
这是一个标准问题,称为producer/consumer queue。 目前 C++ 中的开箱即用解决方案是condition_variable。如果您点击链接,您将找到一个示例解决方案。请注意您缺少的一些功能
始终通过 std::lock_guard 或 std::unique_lock 锁定/解锁。 如果速度很重要,请使用条件变量来控制每个线程何时唤醒或休眠。 必须同步对结构的每次访问。这包括推送/弹出,甚至 const 函数,例如对 empty 的调用。鉴于您的代码在哪里,并且问题是众所周知的。我建议你应该开始寻找现有的代码。从扫描阅读this 看起来像是一个合理的概述。尤其是“有界缓冲区”部分。 Boost 有一些不使用互斥锁的实现。这比您似乎需要的更先进。我不会为您提供建议,但其他人可能会对此感兴趣。 https://www.boost.org/doc/libs/1_54_0/doc/html/boost/lockfree/queue.html
【讨论】:
以上是关于C++中对队列的多线程访问的主要内容,如果未能解决你的问题,请参考以下文章