I have a C++11 program which configures a number of runnable objects, puts them in a std::vector
, then launches them all in separate threads. Unfortunately when I iterate over the objects in the vector, I am getting threads launched only for the last object. I've distilled the problem to its core in the following test code (compiled with clang++ -std=c++11 cpp_threadlaunch.cpp
using clang
6.0 on OSX 10.9.5).
#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);
}
When I run with goal = "succeed"
, I get the hoped-for output
Agent: A
Agent: B
Agent: A
Agent: B
When I run with goal = "fail"
, I get two copies of the output from only one object, instead of output from each object:
Launching thread for A
Launching thread for B
Agent: B
Agent: B
Agent: B
Agent: B
I suspect I'm missing something rudimentary here -- would much appreciate it if someone can explain what's going on and what the solution is. Thanks --
Changing contents of vector of threadvecOfThreads[1] = std::move(th4); //Destructor of already existing thread object will call terminate vecOfThreads[1] = std::move(th4); //Destructor of already existing thread object will call terminate vecOfThreads[1] = std::move(th4);
std::thread is the thread class that represents a single thread in C++. To start a thread we simply need to create a new thread object and pass the executing code to be called (i.e, a callable object) into the constructor of the object.
Yes, you are right. I obviously misunderstood that sentence in the documentation: "No contained elements are accessed: concurrently accessing or modifying them is safe." It probably only means that size() is thread-safe against a concurrent modification of the elements already in the container.
std::thread Threads allow multiple functions to execute concurrently. std::thread objects may also be in the state that does not represent any thread (after default construction, move from, detach, or join), and a thread of execution may not be associated with any thread objects (after detach).
The lambda function you're passing to std::thread
in the loop captures a
by reference. Since a
then goes out of scope you have undefined behavior. Capture it by value (using [=]
instead of [&]
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With