std :: thread在无限循环中随机时间后锁定

时间:2015-08-23 08:52:22

标签: c++ multithreading c++11 mutex

我试图在我的主应用程序中实现3个额外的线程,这些线程执行非共享操作。

起初我认为它正常工作,因为如果我取消注释WorkerThread函数中的最后一个printf调用,它会在一段随机时间后锁定在WaitThread()。如果没有printf,有时需要几秒钟才能锁定mWaitCond.Wait()函数,有时会在启动后立即执行。 printf似乎可以修复线程的时间。

应用程序没有崩溃,只是应用程序的cpu使用率为0%(和每个线程)并且没有响应。在visual studio调试器中停止显示在WaitThread()函数中的行(mWakeUp)mWaitCondition.Wait()作为当前位置。它还表明mWakeUp对于所有线程都是假的,因此它不应该保持在while循环中。

我的设计背后的想法:

  1. 在进入主无限循环之前调用SetupThreads()
  2. 在无限循环中,WorkerInit()被调用为wakup线程
  3. 在我访问3个线程的数据之前,调用WorkerWait()等待它们完成
  4. 在WorkerThread函数内部(由每个线程调用),我锁定互斥锁并等待线程被唤醒或停止
  5. 处理完数据后,wakeUp设置为false,condition_variable通知
  6. 可能是waitthread一个接一个地等待线程并且因为它等待让说在索引0的线程,索引2处的线程继续运行?

        static const ui32 NumContexts = 3;
    
        // array of pointers to threads
        std::thread* mThreadHandles[NumContexts];
    
        // wakup
        std::atomic<bool> mWakeUp[NumContexts];
        std::mutex mWakeMutex[NumContexts];
        std::condition_variable mWakeCondition[NumContexts];
    
        // wait for thread to finish task
        std::mutex mWaitMutex[NumContexts];
        std::condition_variable mWaitCondition[NumContexts];
    
        // stop signal
        std::atomic<bool> mStop[NumContexts];
    
        void Framework::SetupThreading()
        {
            // create and start threads
            for (int i = 0; i < NumContexts; i++)
            {
                this->mWakeUp[i] = false;
                this->mStop[i] = false;
                this->mThreadHandles[i] = new  std::thread(&Framework::WorkerThread, this, reinterpret_cast<void*>(i));
            }
        }
    
        //---------------------------------------------
        void Framework::WakeUpThread(int i)
        {
            {
                //auto lock = std::unique_lock<std::mutex>(this->mWakeMutex[i]);
                std::lock_guard<std::mutex> lock(this->mWakeMutex[i]);
                //printf("Waking up thread %i \n", i);
    
                this->mWakeUp[i] = true;
            }
            this->mWakeCondition[i].notify_one();
        }
    
        // THIS FUNCTION LOCKS
        //---------------------------------------------
        void Framework::WaitThread(int i)
        {
            auto lock = std::unique_lock<std::mutex>(this->mWaitMutex[i]);
            //printf("Waiting for thread %i to finish \n", i);
    
            while (this->mWakeUp[i])
                this->mWaitCondition[i].wait(lock);
    
            //printf("Thread %i finished! \n", i);
        }
    
        //---------------------------------------------
        void Framework::StopThread(int i)
        {
            auto lock = std::unique_lock<std::mutex>(this->mWakeMutex[i]);
            printf("Sending stop signal for thread %i \n", i);
            this->mStop[i] = true;
            this->mWakeCondition[i].notify_one();
        }
    
        //---------------------------------------------
        void Framework::JoinThread(int i)
        {
            printf("Waiting for join of thread %i \n", i);
            this->mThreadHandles[i]->join();
            printf("Thread %i joined! \n", i);
        }
    
        // THESE ARE CALLED IN THE MAIN LOOP
        //---------------------------------------------
        void Framework::WorkerInit()
        {
            for (int i = 0; i < NumContexts; i++)
            {
                this->WakeUpThread(i);
            }
        }
    
        void Framework::WorkerWait()
        {
            for (int i = 0; i < NumContexts; i++)
            {
                this->WaitThread(i);
            }
        }
    
        // THE FUNCTION CALLED BY THE THREADS
        //---------------------------------------------
        void Framework::WorkerThread(LPVOID workerIndex)
        {
            int threadIndex = reinterpret_cast<int>(workerIndex);
            while (threadIndex < NumContexts && threadIndex >= 0)
            {
                {
                    auto lock = std::unique_lock<std::mutex>(this->mWakeMutex[threadIndex]);
                    //printf("thread %i: waiting for wakeup or stop signal...\n", threadIndex);
    
                    // not stopped nor woken up? continue to wait
                    while (this->mWakeUp[threadIndex] == false && this->mStop[threadIndex] == false)
                    {
                        this->mWakeCondition[threadIndex].wait(lock);
                    }
    
                    // stop signal sent?
                    if (this->mStop[threadIndex])
                    {
                        //printf("thread %i: got stop signal!\n", threadIndex);
                        return;
                    }
                    //printf("thread %i: got wakeup signal!\n", threadIndex);
    
                    // lock unlocks here (lock destructor)
                }
    
                //  printf("thread %i: running the task...\n", threadIndex);
    
                 // RUN CODE HERE
    
                    //printf("thread %i finished! Sending signal!...\n", threadIndex);
    
                    // m_wakeup is atomic so there is no concurrency issue with wait()
                    this->mWakeUp[threadIndex] = false;
                    this->mWaitCondition[threadIndex].notify_all();
    
    
            }
        }
    

1 个答案:

答案 0 :(得分:1)

如果线程的CPU使用率为零,则它不会在while循环中旋转,而是在wait()上被阻塞。在wait()取消阻塞之前,不会测试循环条件。

检查调试器中的调用堆栈以验证,暂停的位置可能只是指示您的源代码中的返回位置,而不是当前位置。

还要检查WorkerThread实例的状态 - 它们是否正在运行并调用notify_all()?您的调试器线程是否可识别?

我不确定我是否理解你的设计或意图,但从表面看来它似乎有些过于复杂,并且已经成熟,可能会陷入僵局。