主应用程序处于 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 线程未运行的主要内容,如果未能解决你的问题,请参考以下文章
Boost::Asio : io_service.run() vs poll() 或者我如何在主循环中集成 boost::asio