代码之家  ›  专栏  ›  技术社区  ›  Kari

工作线程在执行过快后永久休眠

  •  1
  • Kari  · 技术社区  · 6 年前

    我正在尝试将线程合并到我的项目中,但有一个问题,即仅使用一个工作线程会使它永久“睡着”。也许我有比赛条件,但就是没注意到。

    我的 PeriodicThreads PeriodicThreads::exec_threads() 被调用时,线程被通知,被唤醒并执行其任务。之后,他们又睡着了。

    这种辅助线程的功能:

    void PeriodicThreads::threadWork(size_t threadId){
        //not really used, but need to decalre to use conditional_variable:
        std::mutex mutex;
        std::unique_lock<std::mutex> lck(mutex);
    
        while (true){
            // wait until told to start working on a task:
            while (_thread_shouldWork[threadId] == false){
                _threads_startSignal.wait(lck);
            }
    
            thread_iteration(threadId);    //virtual function
    
            _thread_shouldWork[threadId] = false;   //vector of flags
            _thread_doneSignal.notify_all();
    
        }//end while(true) - run until terminated externally or this whole obj is deleted 
    }
    

    如您所见,每个线程都在一个标志向量中监视自己的条目,一旦它看到它的标志为true,就执行任务,然后重置它的标志。

    以下是可以唤醒所有线程的函数:

    std::atomic_bool _threadsWorking =false;
    
    //blocks the current thread until all worker threads have completed:
    void PeriodicThreads::exec_threads(){
        if(_threadsWorking ){ 
            throw std::runtime_error("you requested exec_threads(), but threads haven't yet finished executing the previous task!");
        }
    
        _threadsWorking = true;//NOTICE: doing this after the exception check.
    
        //tell all threads to unpause by setting their flags to 'true'
        std::fill(_thread_shouldWork.begin(),  _thread_shouldWork.end(),  true);
        _threads_startSignal.notify_all();
    
        //wait for threads to complete:
    
        std::mutex mutex;
        std::unique_lock<std::mutex> lck(mutex); //lock & mutex are not really used.
    
        auto isContinueWaiting = [&]()->bool{
            bool threadsWorking = false; 
            for (size_t i=0;  i<_thread_shouldWork.size();  ++i){
                threadsWorking |= _thread_shouldWork[i];
            }
            return threadsWorking;
        };
    
        while (isContinueWaiting()){
            _thread_doneSignal.wait(lck);
        }
    
        _threadsWorking = false;//set atomic to false 
    }
    

    调用 exec_threads() while 循环。它的工作线程处理该任务,重置其标志并返回睡眠状态,直到下一个工作线程 执行线程() ,等等。

    然而,在那之后的一段时间,程序突然进入“休眠”,似乎暂停了,但没有崩溃。

    在这样的“休眠”期间,在任何一个 while-loop 我的条件变量从来没有真正导致断点触发。


    main )监视我的 对象。当它进入休眠状态时,我的verify线程不断向控制台输出当前没有线程在运行的消息(the _threadsWorking 周期线程 永久设置为false)。然而,在其他试验中,原子仍然是 true

    奇怪的是如果我强迫 PeriodicThreads::run_thread

    我把每个都包好了 condition_variable 内部有一个while循环,以防止虚假的尾迹触发过渡,以及 notify_all .wait() 它被召唤。 Link

    原因是什么?

    编辑

    atomic_bool 对于1个工作线程,仍然显示相同的问题。

    1 回复  |  直到 6 年前
        1
  •  3
  •   Humphrey Winnebago    6 年前

    所有共享数据都应受到互斥锁的保护。互斥应该(至少)与共享数据具有相同的作用域。

    你的 _thread_shouldWork 容器是共享数据。您可以创建一个全局互斥数组,每个互斥数组都可以保护自己的互斥 元素(见下文注释)。您还应该至少拥有与mutex相同数量的条件变量(可以将一个互斥体与多个不同的条件变量一起使用,但不应将多个不同的互斥体与一个条件变量一起使用。)

    condition_variable 应该保护一个 条件(在本例中,是 _线程应该工作 互斥锁用于保护包含该条件的变量。

    while

    具有本地作用域的互斥锁是一个危险信号!

    在使用数组时,还必须注意错误共享

    https://www.youtube.com/watch?v=dznxqe1Uk3E