在 C++ 之外的线程中启动可运行对象 std::vector
Launching runnable objects in threads out of a C++ std::vector
我有一个 C++11 程序,它配置了许多 运行nable 对象,将它们放在 std::vector
中,然后在单独的线程中启动它们。不幸的是,当我遍历向量中的对象时,我只会为最后一个对象启动线程。我已经在以下测试代码中提炼出问题的核心(在 OSX 10.9.5 上使用 clang
6.0 使用 clang++ -std=c++11 cpp_threadlaunch.cpp
编译)。
#include <iostream>
#include <thread>
#include <vector>
#include <unistd.h>
std::mutex outputlock;
class agent {
public:
agent(std::string name) : m_name(name) {};
~agent(void) {};
void run(void) {
while (1) {
outputlock.lock();
std::cout << "Agent: " << m_name << std::endl;
outputlock.unlock();
sleep(1);
}
}
std::string getName(void) { return m_name; }
private:
std::string m_name;
};
int main()
{
std::vector<std::thread> threads;
std::vector<agent*> agents;
// std::string goal = "succeed";
std::string goal = "fail";
agents.push_back(new agent("A"));
agents.push_back(new agent("B"));
if (goal == "succeed") {
threads.push_back(std::thread([&]() { agents.at(0)->run(); }));
threads.push_back(std::thread([&]() { agents.at(1)->run(); }));
}
else {
for (auto it = agents.begin(); it != agents.end(); it++) {
agent* a = *it;
std::cout << "Launching thread for " << a->getName() << std::endl;
threads.push_back(std::thread([&]() { a->run(); }));
}
}
for (auto it = threads.begin(); it != threads.end(); it++) {
it->join();
}
exit(0);
}
当我 运行 和 goal = "succeed"
时,我得到了希望的输出
Agent: A
Agent: B
Agent: A
Agent: B
当我 运行 和 goal = "fail"
时,我只从一个对象获得输出的两份副本,而不是每个对象的输出:
Launching thread for A
Launching thread for B
Agent: B
Agent: B
Agent: B
Agent: B
我怀疑我在这里遗漏了一些基本的东西——如果有人能解释发生了什么以及解决方案是什么,我将不胜感激。谢谢 --
您在循环中传递给 std::thread
的 lambda 函数通过引用捕获 a
。由于 a
然后超出范围,您有未定义的行为。按值捕获它(使用 [=]
而不是 [&]
)。
问题是您通过引用捕获了 'a' 的值
[&]() { a->run() }
你看到最后一个值,因为循环已经完成,到其他线程 运行 时。
如果按值捕获,使用 [=] 应该会得到预期的效果。
我有一个 C++11 程序,它配置了许多 运行nable 对象,将它们放在 std::vector
中,然后在单独的线程中启动它们。不幸的是,当我遍历向量中的对象时,我只会为最后一个对象启动线程。我已经在以下测试代码中提炼出问题的核心(在 OSX 10.9.5 上使用 clang
6.0 使用 clang++ -std=c++11 cpp_threadlaunch.cpp
编译)。
#include <iostream>
#include <thread>
#include <vector>
#include <unistd.h>
std::mutex outputlock;
class agent {
public:
agent(std::string name) : m_name(name) {};
~agent(void) {};
void run(void) {
while (1) {
outputlock.lock();
std::cout << "Agent: " << m_name << std::endl;
outputlock.unlock();
sleep(1);
}
}
std::string getName(void) { return m_name; }
private:
std::string m_name;
};
int main()
{
std::vector<std::thread> threads;
std::vector<agent*> agents;
// std::string goal = "succeed";
std::string goal = "fail";
agents.push_back(new agent("A"));
agents.push_back(new agent("B"));
if (goal == "succeed") {
threads.push_back(std::thread([&]() { agents.at(0)->run(); }));
threads.push_back(std::thread([&]() { agents.at(1)->run(); }));
}
else {
for (auto it = agents.begin(); it != agents.end(); it++) {
agent* a = *it;
std::cout << "Launching thread for " << a->getName() << std::endl;
threads.push_back(std::thread([&]() { a->run(); }));
}
}
for (auto it = threads.begin(); it != threads.end(); it++) {
it->join();
}
exit(0);
}
当我 运行 和 goal = "succeed"
时,我得到了希望的输出
Agent: A
Agent: B
Agent: A
Agent: B
当我 运行 和 goal = "fail"
时,我只从一个对象获得输出的两份副本,而不是每个对象的输出:
Launching thread for A
Launching thread for B
Agent: B
Agent: B
Agent: B
Agent: B
我怀疑我在这里遗漏了一些基本的东西——如果有人能解释发生了什么以及解决方案是什么,我将不胜感激。谢谢 --
您在循环中传递给 std::thread
的 lambda 函数通过引用捕获 a
。由于 a
然后超出范围,您有未定义的行为。按值捕获它(使用 [=]
而不是 [&]
)。
问题是您通过引用捕获了 'a' 的值
[&]() { a->run() }
你看到最后一个值,因为循环已经完成,到其他线程 运行 时。
如果按值捕获,使用 [=] 应该会得到预期的效果。