我知道书上怎么说std::deque是适度的线程安全,但我的经验证明并非如此。我使用的是VS2010。至少有两个线程(可能是N个线程,但添加线程只会使问题更早发生),每个线程都运行相同的代码。每个线程都包含相同的代码,但是一个指向结构的唯一实例的指针会传递给每个线程,因此在理论上,每个线程都有自己的deque可用。然而,在不同的时间,当线程试图访问双端队列(总是读取)时,我会得到错误。deque的定义如下所示:
struct A
{
deque<TAS*> dqTas;
}TAS是指向另一个结构的指针。
结构A被创建为
A* Aptr = new A; TAS结构也是以同样的方式创建的
TAS* pTas = new TAS这些错误的特征是:
1)它们在代码中随机发生。在错误发生之前,线程可以运行几分钟来处理对双端队列的数据读取/写入。
2)线程越多,问题发生的速度越快。这个问题永远不会在一个线程中发生。
3)错误消息会有所不同,要么是deque不能被解除引用,要么是索引超出了范围。如果发生deque不能取消引用错误,那么检查数据的原因是完全无法检测的。如果问题是索引超出了范围,那么不知何故,一个或多个数据项(数百个数据项中的一个或多个)突然在双队列中被损坏。
我已经删除了每个工作流路径中的所有删除,所以无意中删除内存不会成为问题。
唯一可能导致这种情况的是std::deque代码中的全局计数器或指针。这些错误的字符表示线程冲突源。我甚至验证了每个结构实例的地址是不同的。理论上,冲突的可能性应该为零,因为每个线程都有自己的双线程副本。这种设置的唯一方式是std::deque代码中有一个全局ptr或计数器。
还有没有其他人有过这样的经历?在这种情况下,boost deque函数会表现得更好吗?
如果你想知道,这是gpfs的代码:
pTs->dqTas.push_front( pTb ); <<GPF happens after a write
#if defined (DEBUG)
long d2 = pTs->dqTas.size()-1;
if( d2 > 0 )
{
TASBAR* pDel2;
//pDel2 = pTs->dqTas[d2];
pDel2 = pTs->dqTas.at(d2); //<<GPF happens here
}
#endif解决方案:
感谢大家的评论。问题已经解决了,它与deque容器没有任何关系。随机的deque腐败是这个问题的一个症状。这个问题是由线程实例化的类的函数中本地声明的一些旧的静态变量引起的。这些变量被另一个线程中保存在同一双队列中的其他对象的地址覆盖。我刚刚摆脱了这些,一切都开始像预期的那样工作。尽管听起来很基础,但这里要记住的教训是,静态变量本质上是跨线程的全局变量(即使是在函数中局部定义的)。在任何可以运行同一代码的多个实例的线程中,最好避免使用它们,除非非常清楚它们被使用的原因和方式。
发布于 2014-04-10 08:10:26
一般来说,没有一个容器是“线程安全的”。它只是一个容器。我建议你自己让它成为线程安全的。在堆栈上创建一个带有std::mutex的std::lock_guard对象将使您的代码线程安全。希望它能有所帮助:下面是一个代码示例:
std::mutex lockMutex;
std::lock_guard<std::mutex> lock(lockMutex);https://stackoverflow.com/questions/22976154
复制相似问题