【发布时间】:2019-03-13 00:40:26
【问题描述】:
这是我第一次尝试对我的代码进行多线程处理。
代码包含一个创建单个模拟对象的模拟类。由于我需要运行其中的几个,我想跨多个线程并行运行它们。该代码在串行中工作得非常好,但是当将每个模拟对象方法分配给不同的线程时,我在不同的时间(通常很早)遇到分段错误,我认为这是由于某种数据竞争的发生。再深入一点,我发现一些成员变量似乎被重新初始化或只是改变了值(在每次运行中都不一致)。我很清楚,有些资源混在一起了,但是当我在独立线程中运行每个模拟时怎么会发生这种情况(或者我认为是这样)?
这是代码的简化版本。
模拟类:
class Simulation{
public:
void run(){
//Complicated stuff;
}
};
main.cpp:
int main(){
vector<Simulation> simulations;
vector<thread> threads;
for (int i=0; i<nSimulations; i++){
simulations.push_back(
Simulation(params));
threads.push_back(thread(&Simulation::run,
std::ref(simulations[i])));
}
for (int i=0; i<nSimulations; i++){
threads[i].join();
simulations[i].saveToFile("test.dat");
}
return 0;
}
这段代码有什么本质上的错误吗?实际代码非常复杂,所以至少我想知道这是否是将不同对象方法多线程化到不同线程的正确方法。
【问题讨论】:
-
您不能将
std::ref(simulations[i])作为参数传递给线程,因为模拟是vector,并且在调用push_back方法时,它的元素被重新分配,因此线程对象中指向模拟对象的指针无效。 -
您可以通过保留向量空间轻松防止重新分配:
simulations.reserve(nSimulations);。顺便说一句,使用simulations.back()比simulations[i]更清楚地表达了您的意图。另外,请考虑将emplace_back与两个向量一起使用。 -
您的
Simulation对象没有任何可变成员 - 只有run()。run()是否以某种方式发生了变化,或者您的示例是否不完整且不可重现?我建议您创建一个 minimal reproducible example 来演示该问题。 -
不知道
push_back重新分配向量。 @DanielLangr 使用 simulations.reserve(nSimulations) 解决了这个问题。是否有一种更优雅的方式可以总体上实现相同的结果? -
如果您的
Simulation对象是可复制的,您只需std::vector<Simulation> simulations(n, { params });将它们全部初始化为向量构造函数中的副本。
标签: c++ multithreading class c++11 stdthread