Gio
Gio

Reputation: 3340

How to wait for multiple threads to finish (with c++11 threads)?

I'm trying to write a program which uses c++11 threads functionality in order to spawn multiple threads, the main thread must wait for each spawned thread to be finished, and all spawned threads must run in parallel. I've come up with the following approach:

#include <iostream>
#include <stdio.h>
#include <thread>
#include <condition_variable>
#include <mutex>

using namespace std;

class Producer
{
public:
    Producer(int a_id):
        m_id(a_id),
        m_running(false),
        m_ready(false),
        m_terminate(false)
    {
        m_id = a_id;
        m_thread = thread(&Producer::run, this);
        while (!m_ready) {}
    }

    ~Producer() {
        terminate();
        m_thread.join();
    }

    void wait() {
        unique_lock<mutex> lock(m_waitForRunFinishMutex);
        m_cond.wait(lock);
        // avoid spurious wake up
        if (m_running) {
            wait();
        }
        lock.unlock();
        cout << "wait exit " << m_id << endl;
    }

    void start() {
        m_running = true;
        m_cond.notify_all();
    }

    void terminate() {
        start();
        m_terminate = true;
    }

    void run() {
        m_ready = true;
        do {
            unique_lock<mutex> lock(m_mutex);
            while (!m_running) {
                m_cond.wait(lock);
            }

            if (!m_terminate) {
                cout << "running thread: " << m_id << endl;
            }

            m_running = false;
            m_cond.notify_all();
        } while (!m_terminate);
    }

private:
    int m_id;
    bool m_running;
    bool m_ready;
    bool m_terminate;
    thread m_thread;
    mutex m_mutex;
    mutex m_waitForRunFinishMutex;
    condition_variable m_cond;
};

The program runs fine when testing with just one thread, i.e the following program:

int main()
{
    Producer producer1(1);    
    producer1.start();
    producer1.wait();

    return 0;
}

Results in the following output:

running thread: 1
wait exit: 1

However if I test the program with 2 thread, e.g:

int main()
{
    Producer producer1(1);
    Producer producer2(2);

    producer1.start();
    producer2.start();

    producer1.wait();
    producer2.wait();

    return 0;
}

I get the following output:

running thread: 2
running thread: 1
wait exit 1

It seems producer2 never get notified (in producer2.wait()), and therefore the program never finishes. Hopefully somebody can point out what I'm missing here.

Thanks everybody for the help in addressing the problem. Eventually the root cause of the problem is described in point (3) of the accepted answer. I've solved this by correcting the wait function as follows:

void wait() {
    unique_lock<mutex> lock(m_waitForRunFinishMutex);
    while (m_running) {
        m_cond.wait(lock);
    }
    lock.unlock();
}

Upvotes: 0

Views: 3887

Answers (1)

UKMonkey
UKMonkey

Reputation: 6983

Here's a quick collection of issues from a glance.

  1. wait() is recursive without unlocking its unique lock (as per the comment from Detonar)

  2. while (!m_ready) {} Is not in a memory barrier (try compiling with some optimization and see what happens!)

  3. If the worker thread completes before wait() is called; there is no check performed before waiting on the condition variable. Since the worker thread is complete; it will never get woken. Clearly you must check to see if the thread can get woken up within the mutex before waiting on the condition variable.

Upvotes: 1

Related Questions