我在 OS X 上使用 Boost Asio 时遇到问题,其中 io_service 析构函数有时 无限期挂起。我有一个相对简单的重现案例:
#include <boost/asio.hpp>
#include <boost/thread.hpp>
int main(int argc, char* argv[]) {
timeval tv;
gettimeofday(&tv, 0);
std::time_t t = tv.tv_sec;
std::tm curr;
// The call to gmtime_r _seems_ innocent, but I cannot reproduce without this
std::tm* curr_ptr = gmtime_r(&t, &curr);
{
boost::asio::io_service ioService;
boost::asio::deadline_timer timer(ioService);
ioService.post([&](){
// This will also call gmtime_r, but just calling that is not enough
timer.expires_from_now(boost::posix_time::milliseconds(1));
timer.async_wait([](const boost::system::error_code &) {});
});
ioService.post([&](){
ioService.post([&](){});
});
// Run some threads
boost::thread_group workers;
for (auto i=0; i<3; ++i) {
workers.create_thread([&](){ ioService.run(); });
}
workers.join_all();
} // hangs here in the io_service destructor
return 0;
}
基本上,这只是在队列中发布两个处理程序,其中一个调度计时器,另一个只是发布另一个处理程序。有时这个简单的程序会导致 io_service
析构函数无限期挂起,特别是在 kqueue_reactor
析构期间的 pipe_select_interrupter
析构函数中。这会阻止管道读取描述符上的系统调用 close()
。
为了触发错误,我使用 shell 脚本在循环中调用程序(但也可以在上面的示例中使用循环来触发):
#!/bin/csh
set yname="foo"
while ( $yname != "" )
date
./hangtest
end
如果我出现以下情况,我将无法生育:
- 删除开头对
gmtime_r()
的调用 (!)。编辑:这似乎仅在我使用脚本运行时才适用。如果我改为在程序本身中添加一个循环,我也可以在没有该调用的情况下重现它,根据 ruslo 的评论。 - 删除对处理程序中计时器的
async_wait()
的调用,或将计时器设置移到处理程序之外。 - 删除第二个处理程序中的
post()
。 - 减少线程数。
- 在
kqueue_reactor::interrupt()
中放置一个互斥锁。此函数从async_wait()
和post()
调用,并使用读取描述符调用kevent()
可能关闭。
我在上面的代码中做错了什么吗?
我在带有 Boost 1.54 的 OS X 10.8.5 上运行,并使用 clang -stdlib=libc++ -std=c++11
进行编译。我还可以使用 Boost 1.55 中的 Boost Asio 进行重现(Boost 1.54 的其余部分保持原样)。
编辑:我也可以在 OS X 10.9.1 上重现(使用相同的可执行文件)。
最佳答案
此修复已于 2014 年 4 月 29 日在主分支中提交给 Asio
Fix occasional close() system call hang on MacOS.
Repeated re-registration of kqueue event filters seems to behave as though there is some kind of "leak" on MacOS, culminating in a suspended close() system call and an unkillable process. To avoid this, we will register a descriptor's kqueue event filters once only i.e. when the descriptor is first created.
关于c++ - Boost Asio io_service 析构函数卡在 OS X 上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21835749/