Search code examples
c++multithreadingparallel-processingboost-thread

Boost threads running serially, not in parallel


I'm a complete newbie to multi-threading in C++, and decided to start with the Boost Libraries. Also, I'm using Intel's C++ Compiler (from Parallel Studio 2011) with VS2010 on Vista.

I'm coding a genetic algorithm, and want to exploit the benefits of multi-threading: I want to create a thread for each individual (object) in the population, in order for them to calculate their fitness (heavy operations) in parallel, to reduce total execution time.

As I understand it, whenever I launch a child thread it stars working "in the background", and the parent thread continues to execute the next instruction, right? So, I thought of creating and launching all the child threads I need (in a for loop), and then wait for them to finish (call each thread's join() in another for loop) before continuing.

The problem I'm facing is that the first loop won't continue to the next iteration until the newly created thread is done working. Then, the second loop is as good as gone, since all the threads are already joined by the time that loop is hit.

Here are (what I consider to be) the relevant code snippets. Tell me if there is anything else you need to know.

class Poblacion {
    // Constructors, destructor and other members
    // ...
    list<Individuo> _individuos;
    void generaInicial() { // This method sets up the initial population.
        int i;
        // First loop
        for(i = 0; i < _tamano_total; i++) {
            Individuo nuevo(true);
            nuevo.Start(); // Create and launch new thread
            _individuos.push_back(nuevo);
        }

        // Second loop
        list<Individuo>::iterator it;
        for(it = _individuos.begin(); it != _individuos.end(); it++) {
            it->Join();
        }

        _individuos.sort();
    }
};

And, the threaded object Individuo:

class Individuo {
    private:
        // Other private members
        // ...
        boost::thread _hilo;

    public:
        // Other public members
        // ...
        void Start() {
            _hilo = boost::thread(&Individuo::Run, this);
        }
        void Run() {
            // These methods operate with/on each instance's own attributes,
            // so they *can't* be static
            generaHoc();
            calculaAptitud();
            borraArchivos();
        }
        void Join() {
            if(_hilo.joinable()) _hilo.join();
        }
};

Thank you! :D


Solution

  • If that's your real code then you have a problem.

        for(i = 0; i < _tamano_total; i++) {
            Individuo nuevo(true);
            nuevo.Start(); // Create and launch new thread
            _individuos.push_back(nuevo);
        }
    
        void Start() {
            _hilo = boost::thread(&Individuo::Run, this);
        }
    

    This code creates a new Individuo object on the stack, then starts a thread that runs, passing the thispointer of that stack object to the new thread. It then copies that object into the list, and promptly destroys the stack object, leaving a dangling pointer in the new thread. This gives you undefined behaviour.

    Since list never moves an object in memory once it has been inserted, you could start the thread after inserting into the list:

        for(i = 0; i < _tamano_total; i++) {
            _individuos.push_back(Individuo(true)); // add new entry to list
            _individuos.back().Start(); // start a thread for that entry
        }