C STD ::线程中的种族状况或内存损坏
Race condition or memory corruption in c++ std::thread
我遇到了麻烦,以查明竞赛状况或内存损坏的确切来源。我在代码之后显示了我解决问题的尝试。
我有以下结构:
class A
{
protected:
// various variables
// 1. vector that is assigned value on B, C, D constructor and not
// modified while in thread
// 2. various ints
// 3. double array that is accessed by B, C, D
// here that are used by B, C and D
public:
virtual void execute() = 0;
};
class B : A
{
public:
B(...){};
bool isFinished();
void execute(); //execute does a very expensive loop (genetic algorithm)
}
class C : A
{
public:
C(...){};
bool isFinished();
void execute();
}
class D : A
{
public:
D(...){};
bool isFinished();
void execute();
}
class Worker
{
private:
A& m_a;
Container& m_parent;
public:
// Worker needs a reference to parent container to control a mutex
// in the sync version of this code (not shown here)
Worker(A& aa, Container& parent) : m_a(aa), m_parent(parent) {}
executeAsynchronous();
}
class Container
{
private:
std::vector<Worker> wVec;
public:
addWorker(Worker w); //this does wVec.push_back(w)
start();
}
void Worker::executeAsynchronous(){
while(!a.isFinished())
m_a.execute();
}
void Container::start(){
std::thread threads[3];
for (int i=0; i<wVec.size(); i++){
threads[i] = std::thread(&Worker::executeAsynchronous,
std::ref(wVec[i]));
}
for (int i=0; i<wVec.size(); i++){
threads[i].join();
}
}
要运行代码,我会做:
Container container;
B b(...);
C c(...);
D d(...);
Worker worker1(b, container);
Worker worker2(c, container);
Worker worker3(d, container);
container.addWorker(worker1);
container.addWorker(worker2);
container.addWorker(worker3);
container.start();
代码应该源于异步运行 execute()
,但是我有以下2个问题:
一个线程比2或3或4个线程快和具有更好的结果(通过在1个线程中运行遗传算法而产生的更好的优化(,我读到我可以受到限制通过内存带宽,但是那在哪里?我如何验证这种情况?
两个或多个线程:结果变得非常糟糕,某种程度上有些事情在途中被损坏或陷入困境。但是我无法确定它。我已经从代码的各个位置进行了
cout
,每个线程完全执行一个继承的类的execute()
,即每个线程运行B, C or D
的execute()
,并且不会跳跃或干扰他人。当我将m_parent.mutex.lock()
和m_parent.mutex.unlock()
放在a.execute();
周围的那一刻,有效地使多线程代码单线程变得正确。
我试图:
- 将
Container
推回CC_11的向量后,删除B, C and D
中可能会悬挂的指针。我现在将副本传递给push_back
。 - 使用
emplace_back
代替push_back
,但没有区别 - 使用
vector.reserve()
避免重新分配和丢失参考,但没有差异 - 使用
std::ref()
,因为我发现了std ::螺纹制作副本,我希望修改元素wVec[i]
,以前我只是将wVec[i]
传递给线程。
我相信,通过在上面做1-4,它们没有区别,并且通过单线线程运行代码,并且可以很好地工作,这并不是某种范围的情况。另外,线程或容器之间没有数据交换,我知道std::vector
不是线程安全。
如果您花时间帮助我弄清楚这一点。
edit1:根据康斯坦丁的通知,这是我的RandomNumberGenerator类,它是一个静态类,我使用RandomNumberGenerator::getDouble(a,b)
//rng.h
class RandomNumberGenerator
{
private:
static std::mt19937 rng;
public:
static void initRNG();
static int getInt(int min, int max);
static double getDouble(double min, double max);
};
//rng.cpp
std::mt19937 RandomNumberGenerator::rng;
void RandomNumberGenerator::initRNG()
{
rng.seed(std::random_device()());
}
int RandomNumberGenerator::getInt(int min, int max)
{
std::uniform_int_distribution<std::mt19937::result_type> udist(min, max);
return udist(rng);
}
double RandomNumberGenerator::getDouble(double min, double max)
{
std::uniform_real_distribution<> udist(min, max);
return udist(rng);
}
edit2:我解决了损坏问题。这是我错过的非线程安全功能的呼吁(评估功能(。至于缓慢,在线程中运行时,程序仍然很慢。我已经运行了Valgrind的callgrind
,并使用gprof2dot
绘制了结果,并且看来M4RC的建议保留。有很多STL容器调用,我将尝试动态分配数组。
edit3:正如康斯坦丁·潘(Constantin Pan(指出的那样,RNG类是罪魁祸首。使用gprof
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls s/call s/call name
17.97 70.09 70.09 1734468 0.00 0.00 std::mersenne_twister_engine //SYNC
18.33 64.98 64.98 1803194 0.00 0.00 std::mersenne_twister_engine //ASYNC
6.19 63.41 8.93 1185214 0.00 0.00 std::mersenne_twister_engine //Single thread
edit4 :Deque容器也有罪-M4RC
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls s/call s/call name
14.15 28.60 28.60 799662660 0.00 0.00 std::_Deque_iterator
sice涉及遗传算法,请确保随机数生成器是螺纹保护的。过去,我用cstdlib
的rand()
来打击了这个(放缓和不正确的结果(。
- 如何针对特定情况调试和修复此双自由内存损坏问题
- 正在调试 malloc():新内存损坏
- 仅特定内核计数上的 MPI 内存损坏
- C++程序错误:malloc():内存损坏
- 调用std::函数成员时内存损坏
- C++ 内存损坏检测
- 由于标头中的 #define 不匹配而导致内存损坏
- C STD ::线程中的种族状况或内存损坏
- malloc()内存损坏仅通过为特定数量编写int数组
- 字符串标记化期间的内存损坏
- 从检测到 glibc 正常退出 - malloc():内存损坏
- 放置在外部 DLL 中的类中的字符串数据的内存损坏
- std :: string ::擦除会导致内存损坏
- 编译器如何检测内存损坏
- mix_playMusic导致内存损坏
- 在使用新操作员和C 中的结构的调用构造函数时,获得内存损坏(Malloc)
- 两个内联程序集调用与一个内联程序集调用中的内存损坏?
- 如何调试不确定内存损坏?
- 增强Dijkstra代码会导致片段内存损坏
- 内存损坏从vb.net调用c dll