【问题标题】:condition_variable::wait_for method not returning - even after the timeoutcondition_variable::wait_for 方法没有返回 - 即使在超时之后
【发布时间】:2015-11-23 17:34:11
【问题描述】:

我有 C# 编码经验;我开始学习 C++ 并使用 boost 库进行线程处理。 我编写了以下类 - 尝试将成员函数作为线程执行。编写以下简单代码,我希望线程函数内的 while 循环每秒执行一次。

#include <boost/chrono/chrono.hpp>
#include <boost/thread/thread.hpp>
#include <iostream>

using namespace boost;

class MyClassWithThread : public boost::enable_shared_from_this<MyClassWithThread>
{ 
    mutex                           muThreadControl;
    condition_variable              cvThreadControl;
    bool                            threadToBeStopped = false; 

    void ThreadFunction()
    {
        std::cout << "Beginning the Thread" << std::endl;

        while(true)
        {
            bool endIOThread = false;
            std::cout << "\nChecking if Thread to be stopped: ";
            {
                boost::mutex::scoped_lock lock(muThreadControl);
                endIOThread = cvThreadControl.wait_for(lock, 
                    boost::chrono::seconds(1),
                    [this]{return threadToBeStopped;} ) == cv_status::no_timeout;
                std::cout << endIOThread << std::endl
            }
        }
        std::cout << "Exiting the Thread" << std::endl;
    }

public:
    thread                          threadRunner; 
    MyClassWithThread()
    { 
        threadRunner = thread(&MyClassWithThread::ThreadFunction, this);
    }
};


int main(int argc, char* argv[])
{
    MyClassWithThread myclassWithThread;
    myclassWithThread.threadRunner.join();
    return 0;
}

在 Linux 上构建:

g++ -std=c++11 -pthread cond-wait-test.cpp -o cond-wait-test -lboost_system -lboost_thread -lboost_chrono

但是,当我执行代码时,我只注意到线程执行在调用 wait_for 方法时被阻塞;永远。尽管有超时时间。此外,系统的资源监视器显示处理器内核正在 100% 使用。

谁能解释一下代码中发生了什么?

【问题讨论】:

  • 看起来没有任何东西可以退出您的 while 循环。
  • 如果它使用 100% CPU 那么它不会被阻塞。谓词检查或超时一定有问题。
  • @MohamadElghawi,上面的代码用于测试目的;我希望控制台打印:检查线程是否停止:0 检查线程是否停止:0 检查线程是否停止:0...
  • @ZanLynx,100% CPU 利用率不是预期的迹象,因为我希望它只等待一秒钟(睡眠)。根本不应该消耗任何CPU..
  • @rat6:既然它对我有用,也许你需要包括你的编译器、操作系统和 Boost 版本的详细信息。

标签: c++ multithreading boost


【解决方案1】:

正如@Zan Lynx 所建议的,罪魁祸首是#pragma pack 声明。我最初只使用#pragma pack(1) 来对某些结构进行字节对齐。这影响了许多互斥体结构到 1 字节对齐。

我将#pragma pack(1) 语句更改为#pragma pack(push, 1) #pragma pack(pop)。它一切正常。因此我的问题解决了;我学到了一些东西。多谢。 ! :-)

【讨论】:

    【解决方案2】:

    你的程序永远不会退出你的 while 循环。

    解决方案。

    添加某种终止条件。

    bool endIOThread = false;
    while(!endIOThread)
    {
        std::cout << "\nChecking if Thread to be stopped: ";
        {
            boost::mutex::scoped_lock lock(muThreadControl);
            endIOThread = cvThreadControl.wait_for(lock, 
                boost::chrono::seconds(1),
                [this]{return threadToBeStopped;} ) == cv_status::no_timeout;
            std::cout << endIOThread << std::endl
        }
    }
    

    【讨论】:

    • 我认为他想要一个用于测试目的的无限循环,该循环应该每秒打印一次“正在检查...”。在这个测试中,条件永远不会变为真。
    • 以上代码用于测试目的;我希望控制台打印:检查线程是否停止:0 检查线程是否停止:0 检查线程是否停止:0...
    • 我知道条件永远不会为真,线程函数永远不会真正完成。但我想知道为什么它不每秒打印“检查线程是否停止”消息?
    【解决方案3】:

    我复制了你的代码并在 Linux 上尝试过。

    您发布的代码将无法编译。不知道你试过没?

    问题是带有谓词重载的wait_for 返回bool 而不是cv_status。内循环超时,调用谓词并返回。

    如果我删除谓词 lambda,您的代码将按预期工作。如果我离开 lambda 并删除 ==cv_status 的比较,它也可以工作。

    也许如果你按照我的做法删除using namespace boost; 行,然后明确所有 Boost 对象。

    这是适合我的修改版本:

    #include <boost/chrono/chrono.hpp>
    #include <boost/thread/thread.hpp>
    #include <iostream>
    
    class MyClassWithThread : public boost::enable_shared_from_this<MyClassWithThread>
    {
        boost::mutex                           muThreadControl;
        boost::condition_variable              cvThreadControl;
        bool                            threadToBeStopped = false;
    
        void ThreadFunction()
        {
            std::cout << "Beginning the Thread" << std::endl;
    
            while(true)
            {
                bool endIOThread = false;
                std::cout << "\nChecking if Thread to be stopped: ";
                {
                    boost::mutex::scoped_lock lock(muThreadControl);
    #if 1
                    endIOThread = cvThreadControl.wait_for(lock,
                        boost::chrono::seconds(1),
                        [this]{return threadToBeStopped;} );
    #else
                    endIOThread = cvThreadControl.wait_for(lock,
                        boost::chrono::seconds(1)) == boost::cv_status::no_timeout;
                    std::cout << endIOThread << std::endl;
    #endif
                }
            }
            std::cout << "Exiting the Thread" << std::endl;
        }
    
    public:
        boost::thread                          threadRunner;
        MyClassWithThread()
        {
            threadRunner = boost::thread(&MyClassWithThread::ThreadFunction, this);
        }
    };
    
    
    int main(int argc, char* argv[])
    {
        MyClassWithThread myclassWithThread;
        myclassWithThread.threadRunner.join();
        return 0;
    }
    

    Linux GCC 构建命令:

    g++ -std=c++11 -pthread cond-wait-test.cpp -o cond-wait-test -lboost_system -lboost_thread -lboost_chrono
    

    【讨论】:

    • 感谢您的回复。你说的对;在发布这个问题时,我围绕检查 wait_for 的返回类型修改了代码。我删除了 using 声明并使用 boost::*** 显式声明了变量。但我仍然没有看到打印的“正在检查..”消息。
    • 嗨@Zan,我看到源中列出的文件工作正常。但是,当我包含更多头文件时,它的行为开始与我最初所说的相同。看到这种行为我感到非常困惑 - 仅仅包含几个头文件会如何影响这种方式?
    • @rat6:如果包含更多头文件时行为发生变化,我将首先删除所有 using namespace 行。新的标头可能会引入一个命名函数,该函数会覆盖您认为您正在调用的函数。接下来,阅读您正在调用的标头/库的所有文档,因为新标头可能正在重新定义预处理器值或启用您没想到的替代功能。
    • 感谢您的建议。经过大量的试验和错误后,我意识到“我的”源代码文件之一包含一个用#pragma pack(1) 定义的结构。当我删除#pragma pack 语句时,程序按预期完美运行。但是一旦启用了语句 - pragma pack(1),condition_variable 的 wait_for 方法就会永远停止。然而,我需要定义结构元素包装;无法避免。你能帮忙解释一下发生了什么吗?
    • @rat6 听起来你打包了所有互斥体结构定义。使用 pack push 和 pack pop。 Pop 会将包装设置回之前的状态。
    猜你喜欢
    • 2017-05-14
    • 2020-02-19
    • 2015-02-27
    • 2017-06-24
    • 2013-10-20
    • 2021-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多