Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Launching runnable objects in threads out of a C++ std::vector

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 --

like image 402
lcikgl Avatar asked Dec 10 '15 22:12

lcikgl


People also ask

How do you create a vector thread in C++?

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);

How do you use std threads in C++?

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.

Is STD vector size thread safe?

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.

What does std :: thread do?

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).


1 Answers

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 [&]).

like image 172
Kevin Avatar answered Sep 19 '22 09:09

Kevin