【问题标题】:Threads - Odd Thread locking issue线程 - 奇数线程锁定问题
【发布时间】:2018-07-28 11:25:36
【问题描述】:

我正在尝试编写一个线程池/管理器,它可以向线程发出信号以执行大量工作,然后在完成后获得回调。不幸的是,如果我调用信号并等待几百次,它最终会失败。下面是实现:

class ThreadManager{
public:
    std::vector<std::thread> threads;
    std::vector<bool> threadCompletes;

    std::mutex sendMtx, recvMtx, boolLock;
    std::condition_variable sendCv;

    static std::string printBool(std::vector<bool>& bools){
        std::string xx;
        for(int i=0; i<bools.size(); i++){
            if(bools[i]) xx += "1"; else xx+="0";
        }
        return xx;
    }

    static void thread_worker(int id, ThreadManager* manager){

        while(1){
            std::unique_lock<std::mutex> lck(manager->sendMtx);
            //cout << "Thread Wait: " << id << endl;
            manager->sendCv.wait(lck);
            lck.unlock();
            // DO WORK
            //std::this_thread::sleep_for(std::chrono::milliseconds(10));
            manager->boolLock.lock();
            cout << "Start ParOp..: " << id << endl;
            manager->boolLock.unlock();

            std::this_thread::sleep_for(std::chrono::milliseconds(10));

            manager->boolLock.lock();
            manager->threadCompletes[id] = true;
            bool done = (std::find(std::begin(manager->threadCompletes), std::end(manager->threadCompletes), false) == std::end(manager->threadCompletes));
            cout << "Job Complete: " << id << " " << printBool(manager->threadCompletes) << endl;
            manager->boolLock.unlock();
            if(done){
                cout << "All Done" << endl;
                manager->recvMtx.unlock();
            }
        }
    }

    ThreadManager(){

    }

    void addThread(){
        threadCompletes.push_back(false);
        threads.push_back(std::thread(ThreadManager::thread_worker, threads.size(), this));
    }

    void signal(){
        boolLock.lock();
        for(auto i : threadCompletes) i = 0;
        boolLock.unlock();
        recvMtx.lock();
        std::unique_lock<std::mutex> sendLck(sendMtx);
        sendCv.notify_all();
        sendLck.unlock();
    }

    void wait(){
        recvMtx.lock();
        recvMtx.unlock();
    }

    void join(){
        for (int i = 0; i < threads.size(); ++i) {
            threads[i].join();
        }
    }
};


void test2(){

    ThreadManager manager;
    for(int i=0; i<8; i++){
        manager.addThread();
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(1000));

    for(int i=0; i<500; i++){
        manager.signal();
        manager.wait();
        cout << "\nComplete: " << i << endl;
    }

    cout << "ALL DONE" << endl;

    manager.join();

}

从代码中可以看出,我尝试循环 signal() 和 wait() 500 次。通常在某个随机点,其中一个线程将无法接收到等待信号,它将永远阻塞,从而导致代码失败。这是输出:

Complete: 68
Start ParOp..: 0
Start ParOp..: 2
Start ParOp..: 1
Start ParOp..: 6
Start ParOp..: 3
Start ParOp..: 7
Start ParOp..: 4
Start ParOp..: 5
Job Complete: 0 10000000
Job Complete: 2 10100000
Job Complete: 1 11100000
Job Complete: 6 11100010
Job Complete: 7 11100011
Job Complete: 3 11110011
Job Complete: 4 11111011
Job Complete: 5 11111111
All Done

Complete: 69
Start ParOp..: 0
Start ParOp..: 2
Start ParOp..: 1
Start ParOp..: 6
Start ParOp..: 7
Start ParOp..: 3
Start ParOp..: 4
Job Complete: 0 10000000
Job Complete: 2 10100000
Job Complete: 1 11100000
Job Complete: 7 11100001
Job Complete: 4 11101001
Job Complete: 3 11111001
Job Complete: 6 11111011

如您所见,循环 68 成功,但循环 69 失败,因为线程 5 未能接收到信号,并且永远阻塞等待。为什么会这样

【问题讨论】:

  • 我认为问题是我无法找到一种方法让所有线程在我再次发出信号之前等待,我该怎么做

标签: multithreading c++11


【解决方案1】:
while(1)

没有任何退出方式(通过异常或中断)的无限循环是未定义的行为。

for(auto i : threadCompletes) i = 0;

这条线什么也不做。使用引用来修改值

for (auto& i : threadCompletes) i = false;

我对线程不是那么热衷,但这看起来像是设计上的缺陷。

void wait(){
    recvMtx.lock();
    recvMtx.unlock();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-28
    • 1970-01-01
    • 1970-01-01
    • 2016-08-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多