【发布时间】:2016-08-14 05:17:53
【问题描述】:
主题说了算。我不明白为什么 std::queue(或一般来说:任何队列)本质上不是线程安全的,因为没有像其他数据结构那样涉及迭代器。
根据一般规则
- 至少有一个线程正在写入...
- 另一个线程正在从共享资源中读取数据
我应该在以下示例代码中遇到冲突:
#include "stdafx.h"
#include <queue>
#include <thread>
#include <iostream>
struct response
{
static int & getCount()
{
static int theCount = 0;
return theCount;
}
int id;
};
std::queue<response> queue;
// generate 100 response objects and push them into the queue
void produce()
{
for (int i = 0; i < 100; i++)
{
response r;
r.id = response::getCount()++;
queue.push(r);
std::cout << "produced: " << r.id << std::endl;
}
}
// get the 100 first responses from the queue
void consume()
{
int consumedCounter = 0;
for (;;)
{
if (!queue.empty())
{
std::cout << "consumed: " << queue.front().id << std::endl;
queue.pop();
consumedCounter++;
}
if (consumedCounter == 100)
break;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
std::thread t1(produce);
std::thread t2(consume);
t1.join();
t2.join();
return 0;
}
一切似乎都运行良好: - 没有违反完整性/数据损坏 - 消费者获取它们的元素的顺序是正确的(0
【问题讨论】:
-
简单示例:致电
q.empty()。如果其他东西可以同时从队列中添加或删除元素,结果意味着什么?该界面不是为并发使用而设计的。 -
线程安全通常会产生非常大的开销,在没有线程的情况下完全未使用。另外,作为Java found with synchronizing vector,大多数时候需要保护的是事务,而不是个人访问。
-
一方面,即使
std::queue()就其方法而言是线程安全的,它怎么可能防止在调用front()和@987654327 之间将项目添加到队列中@?如果您运行程序足够长的时间,您至少应该在输出中看到缺少的 ID,因为在打印一个元素的 ID 时,生产者线程添加了另一个元素,然后在打印它的 ID 之前弹出了一个元素(您会看到刚刚打印的 ID 的副本,因为它不会在适当的时间弹出)。 -
如果一切看似正常的事情实际上都做了,我们就不需要定期更新软件了。
-
@Stefano:应该注意的是,该文章中的技术依赖于 MSVC++ 如何处理
volatile变量的非标准细节,即使使用 MSVC++ 也可能取决于目标和/或正在使用的编译器选项:msdn.microsoft.com/en-us/library/12a04hfd.aspx
标签: c++ multithreading queue