主应用程序处于 while 循环时,boost 线程未运行

Posted

技术标签:

【中文标题】主应用程序处于 while 循环时,boost 线程未运行【英文标题】:boost thread not running whilst main application is in a while loop 【发布时间】:2013-01-09 13:16:41 【问题描述】:

我对使用 boost 线程还很陌生。我几乎有一些东西正在运行,但遇到了一个绊脚石:任何帮助将不胜感激。

我有一个 VC++(VS2010 Windows 窗体)应用程序。在不久的将来,这需要移植到 C++ 和 Linux,所以我正在使用 boost 库来处理线程之类的事情,以“简化”移植。

我在一个执行一些 i/o 的类中有一个工作函数:

void myClass::doIO

    while (!boolKillthread)


    //do some work

    //sleep thread 
    boost::this_thread::sleep_for(boost::chrono::milliseconds(333));
    

在 boost 线程中启动:

boost::thread m_MyThread;
m_MyThread = boost::thread(boost::bind(&myClass::doIO));

这工作得很好,正在轮询 i/o 端口,并完美地回调到父类。但是:

我有另一个函数需要在 doIO 线程上等待才能执行一些工作,所以我有一个函数,代码如下:

while (myClass.IsWorkDone() == true)

    //hang a around a while

    //lines commented out below have been tried, but don't resolve the problem
    //boost::this_thread::yield();
    //boost::this_thread::sleep(boost::posix_time::milliseconds(50));
    //boost::this_thread::sleep_for(boost::chrono::milliseconds(50));


问题是,只要我的代码进入 while 循环,boost 线程 doIO 就会停止 - 几乎就像它没有在自己的线程中运行一样!我已经尝试按照上面注释掉的行插入睡眠和产量,但无济于事。

有什么想法吗?


感谢大家的回复:是的,(伪代码)“IsWorkDone”只是返回一个变量,所以我理解(并且现在已经尝试过)使用 boost::mutex::scoped_lock 来更新该变量,所以我们有像

bool myWorkIsDone = false;

bool myClass::IsWorkDone return myWorkIsDone; 



void myClass::doIO

    while (!boolKillthread)


    //do some work
    if (SomeCondition)
        boost::mutex::scoped_lock lock(myMutex);
        myWorkIsDone = true;
    

    //sleep thread 
    boost::this_thread::sleep_for(boost::chrono::milliseconds(333));
    

这很好,但关键是(除非我遗漏了一些明显的东西,这很可能)当我的主代码在循环中时,线程似乎没有运行

while (myClass.IsWorkDone() == true)

    //hang a around a while


因为 IDE 通常会在 doIO 中的断点处停止,但在上述 while 循环中执行时不会。

实际上没有更多(相关的)代码要添加 - 它应该很简单,但它不起作用!

【问题讨论】:

IO 操作中有互斥体吗? 我不得不猜测答案中的问题,因为这里没有足够的代码可以知道。 ::boost::thread 绝对总是创建一个新的执行线程。所以你的代码一定是做错了什么。 可以强行闯入其他线程吗?顺便说一句,boolKillthread 会遇到与myWorkIsDone 相同的问题,但这可能不是您的问题。您的另一个线程显然阻塞了某些东西。显而易见的选择是它阻塞了 IO,但也许它正在等待互斥锁或其他东西。随着“做一些工作”的全部注释掉,这个线程应该可以正常工作。我敢打赌,如果你删除原始代码中的所有工作,它会的。 @Omnifarious:感谢您的帮助。我已经用一个虚拟函数重新创建了 mymain doIO 来测试其他东西正在阻塞的理论——这似乎确实是这样。使用条带化的 doIO 函数,线程似乎运行正常。 (我现在的挑战是弄清楚是什么——但那是另一回事了!) 【参考方案1】:

IsWorkDone 是什么样的?是不是像这样:

 bool IsWorkDone() const  return workdone_; 

因为如果是这样,那就是你的问题。您需要使用互斥锁来包装对workdone_ 的访问。那是共享状态,共享状态需要互斥体。编译器可能正在读取循环顶部的变量,并且不再费心再次读取它。毕竟,据它所知,根本没有理由改变它,所以再读一遍也没有意义。

即使它再次读取它,CPU 也有一个很好的缓存行来保存它,它可能永远不会被刷新,所以你只是在读取它。

哦,当你设置它时,它也需要一个互斥锁。

将其设为::std::atomic<bool> 实际上是一个更好的主意,但我猜你还没有。

【讨论】:

好的,对互斥锁了解了,谢谢,我试试。但是 - 如果我在我的 doIO 函数中放置一个断点,它会在正常(UI 空闲)执行期间被击中,但当代码是 while (myClass.IsWorkDone() == true) ... 循环。 不需要互斥锁, volatile 可以代替。 vloatile 关键字指示编译器可以从外部更改变量,因此不能积极缓存或优化。 呃,没有。 volatile 对于多线程来说是错误的。它会在 Visual Studio 中做正确的事情,但在 GCC 中不会。而且由于他正在移植,因此引入 VS 依赖项是错误的方法。 std::atomic 是一个更好的主意,但这当然需要将 VS 更新到 2012 年。 @Lazin:这是一个非常错误的答案。危险的错误,因为它看起来表面上是正确的。它完全无法解决缓存行问题。是的,其他评论者是正确的,::std::atomic 会起作用,但我假设没有 C++11,因为 OP 使用的是::boost::thread @Zippy:你没有显示足够的代码让我告诉你那里出了什么问题。

以上是关于主应用程序处于 while 循环时,boost 线程未运行的主要内容,如果未能解决你的问题,请参考以下文章

7.2 while 循环简介

Boost::Asio : io_service.run() vs poll() 或者我如何在主循环中集成 boost::asio

循环调用 boost io_service poll

当 ExecuteScript(setInterval) 完成时继续 `while` 循环

在 C++ 中使用 boost 与可执行文件交互

C while 循环仅在语句为真时运行?