这是一个错误。我已经能够通过在task_io_service::do_poll_one
. 这是修改的task_io_service::do_poll_one()
片段booost/asio/detail/impl/task_io_service.ipp
。唯一添加的行是睡眠。
std::size_t task_io_service::do_poll_one(mutex::scoped_lock& lock,
task_io_service::thread_info& this_thread,
const boost::system::error_code& ec)
{
if (stopped_)
return 0;
operation* o = op_queue_.front();
if (o == &task_operation_)
{
op_queue_.pop();
lock.unlock();
{
task_cleanup c = { this, &lock, &this_thread };
(void)c;
// Run the task. May throw an exception. Only block if the operation
// queue is empty and we're not polling, otherwise we want to return
// as soon as possible.
task_->run(false, this_thread.private_op_queue);
boost::this_thread::sleep_for(boost::chrono::seconds(3));
}
o = op_queue_.front();
if (o == &task_operation_)
return 0;
}
...
我的测试驱动程序相当基础:
- 通过将打印“。”的计时器的异步工作循环。每 3 秒。
- 生成一个将轮询
io_service
.
- 延迟以允许新线程有时间进行轮询,并在轮询线程休眠时进行
io_service
主调用。io_service::run()
task_io_service::do_poll_one()
测试代码:
#include <iostream>
#include <boost/asio/io_service.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
boost::asio::io_service io_service;
boost::asio::steady_timer timer(io_service);
void arm_timer()
{
std::cout << ".";
std::cout.flush();
timer.expires_from_now(boost::chrono::seconds(3));
timer.async_wait(boost::bind(&arm_timer));
}
int main()
{
// Add asynchronous work loop.
arm_timer();
// Spawn poll thread.
boost::thread poll_thread(
boost::bind(&boost::asio::io_service::poll, boost::ref(io_service)));
// Give time for poll thread service reactor.
boost::this_thread::sleep_for(boost::chrono::seconds(1));
io_service.run();
}
和调试:
[twsansbury@localhost 错误]$ gdb a.out
...
(gdb) r
启动程序:/home/twsansbury/dev/bug/a.out
[启用使用 libthread_db 进行线程调试]
.[新线程 0xb7feeb90 (LWP 31892)]
[线程 0xb7feeb90 (LWP 31892) 已退出]
至此,arm_timer()
已经打印出“.”。一次(当它最初武装时)。轮询线程以非阻塞方式为反应器提供服务,并在op_queue_
空时休眠 3 秒(task_operation_
将添加回退出范围op_queue_
时)。task_cleanup c
当op_queue_
为空时,主线程调用io_service::run()
,看到op_queue_
为空,并使其自身成为first_idle_thread_
,它在那里等待它的wakeup_event
。轮询线程完成休眠并返回0
,让主线程等待wakeup_event
。
等待 10~ 秒后,有足够的时间arm_timer()
准备好,我中断调试器:
程序接收信号 SIGINT,中断。
__kernel_vsyscall()中的0x00919402
(gdb) BT
#0 0x00919402 在 __kernel_vsyscall ()
#1 0x0081bbc5 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/libpthread.so.0
#2 0x00763b3d 在来自 /lib/libc.so.6 的 pthread_cond_wait@@GLIBC_2.3.2 ()
#3 0x08059dc2 in void boost::asio::detail::posix_event::wait >(boost::asio::detail::scoped_lock&) ()
#4 0x0805a009 in boost::asio::detail::task_io_service::do_run_one(boost::asio::detail::scoped_lock&, boost::asio::detail::task_io_service_thread_info&, boost::system::error_code const&) ( )
#5 0x0805a11c 在 boost::asio::detail::task_io_service::run(boost::system::error_code&) ()
#6 0x0805a1e2 in boost::asio::io_service::run() ()
#7 0x0804db78 in main()
并排时间表如下:
投票线程 | 主线程
----------------------------------------------------+--------- -----------------------------------------
锁() |
do_poll_one() |
|-- 从 | 弹出任务操作_
| queue_op_ |
|-- 解锁() | 锁()
|-- 创建任务清理 | do_run_one()
|-- 服务反应堆(非阻塞) | `-- queue_op_ 为空
|-- ~task_cleanup() | |-- 设置线程为空闲
| |-- 锁() | `--解锁()
| `-- queue_op_.push( |
| 任务操作_) |
`-- task_operation_ 是 |
queue_op_.front() |
`-- 返回 0 | // 仍在等待 wakeup_event
解锁() |
据我所知,修补没有副作用:
if (o == &task_operation_)
return 0;
到:
if (o == &task_operation_)
{
if (!one_thread_)
wake_one_thread_and_unlock(lock);
return 0;
}
Regardless, I have submitted a bug and fix. Consider keeping an eye on the ticket for an official response.