解决死锁问题,在主线程中等待多个工作线程完成(C ++ 11)

时间:2018-01-02 16:55:55

标签: c++ multithreading c++11

我正在尝试用c ++ 11编写一个程序,其中运行多个线程,并且在每个循环中主线程将等待每个线程完成。下面的程序是这个概念的测试程序。

显然我在实现中遗漏了一些微不足道的东西,因为看起来我遇到了死锁(并不总是,只是在一些随机运行期间)。

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

using namespace std;

class Producer
{
public:
    Producer(int a_id):
        m_id(a_id),
        m_ready(false),
        m_terminate(false)
    {
        m_id = a_id;
        m_thread = thread(&Producer::run, this);
        // ensure thread is available before it is started
        this_thread::sleep_for(std::chrono::milliseconds(100));
    }

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

    void start() {
        //cout << "start " << m_id << endl;
        unique_lock<mutex> runLock(m_muRun);
        m_ready = true;
        runLock.unlock();
        m_cond.notify_all();
    }

    void wait() {
        cout << "wait " << m_id << endl;
        unique_lock<decltype(m_muRun)> runLock(m_muRun);
        m_cond.wait(runLock, [this]{return !m_ready;});
    }

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

    void run() {
        do {
            unique_lock<decltype(m_muRun)> runLock(m_muRun);
            m_cond.wait(runLock, [this]{return m_ready;});

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

            runLock.unlock();
            m_ready = false;
            m_cond.notify_all();
        } while (!m_terminate);
    }

private:
    int m_id;
    bool m_ready;
    bool m_terminate;
    thread m_thread;

    mutex m_muRun;
    condition_variable m_cond;
};

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

    for (int i=0; i<10000; ++i) {
        cout << i << endl;
        producer1.start();
        producer2.start();
        producer3.start();

        producer1.wait();
        producer2.wait();
        producer3.wait();
    }

    cout << "exit" << endl;
    return 0;
}

发生死锁时程序的输出:

....
.......
running thread: 2
running thread: 1
wait 1
wait 2
wait 3
running thread: 3

查看死锁发生时程序的输出,我怀疑程序的瓶颈是有时在相应的线程实际启动之前调用Producer::wait函数,即命令Producer::start应该已经触发了开始,是的解锁互斥锁,但线程的运行方法(Producer::run)还没有找到它,(注意:我不是100%肯定这个!)。我在这里有点失落,希望有人可以提供一些帮助。

1 个答案:

答案 0 :(得分:1)

此代码中有竞争条件:

   runLock.unlock();
   m_ready = false;

m_ready变量必须始终受互斥锁保护才能正常同步。并且完全没有必要等待线程启动this_thread::sleep_for() - 正确的同步也会处理它,所以你可以简单地删除该行。注意这是进行适当多线程的非常低效的方法 - 应该有线程池而不是单独的对象,每个对象都有单独的互斥和条件变量。