我正在使用deadline_timer作为异步事件,并且我遇到这样的情况,经过一段时间后,等待事件的线程似乎永远不会被唤醒(尽管有更多调用cancel()).我已经能够使用我在下面粘贴的一些示例代码重现这一点;它并不完全一致,但我已经看到了我认为与我遇到的问题相同的问题.
boost::asio::io_service io_service;
boost::asio::deadline_timer timer(io_service);
timer.expires_at(boost::posix_time::pos_infin);
int num_events = 0;
auto waiter = [&timer, &num_events](boost::asio::yield_context context) {
while (true) {
std::cout << "waiting on event" << std::endl;
boost::system::error_code e;
timer.async_wait(context[e]);
std::cout << "got event (" << e << ")" << std::endl;
++num_events;
}
};
boost::asio::spawn(io_service, std::move(waiter));
boost::thread thread(boost::bind(&boost::asio::io_service::run, &io_service));
for (auto i = 0; i < 500000; ++i) {
timer.cancel();
std::cout << i << std::endl;
}
我在这里做的事情是不受支持的,无意中遇到了一些竞争条件?来自wait()的错误代码从来看起来并不麻烦(即使是在最后一次它再次出现之前就已经被唤醒了).编辑:我也注意到3个不同平台(Windows,Mac和Linux)上的原始错误,但我一直用于重现的上述测试已经在Windows上.
最佳答案 deadline_timer对象不是线程安全的.
你从另一个线程取消它而不是发布async_wait的线程.这意味着电话可以比赛.
我不确定这样可以完全抑制样本中的回调.在我看来程序应该/只是/退出因为500000的紧密循环快速完成(执行许多永远不会被处理的冗余取消,因为协程将例如甚至没有发布新的async_wait).
所以,也许你的意思是“为什么我不能获得500000个活动”.
UPDATE
在评论之后,这是一个微不足道的转变,展示了如何在演员中调用计时器上的成员.注意:这关键取决于io_service仅从单个线程运行的想法!
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/make_shared.hpp>
#include <boost/thread.hpp>
#include <iostream>
using boost::thread;
using boost::asio::io_service;
int main() {
boost::asio::io_service io_service;
boost::asio::deadline_timer timer(io_service);
timer.expires_at(boost::posix_time::pos_infin);
boost::atomic_bool shutdown(false);
int num_events = 0;
auto waiter = [&timer, &num_events, &shutdown](boost::asio::yield_context context) {
while (!shutdown) {
std::cout << "waiting on event" << std::endl;
boost::system::error_code e;
timer.async_wait(context[e]);
std::cout << "got event (" << e.message() << ")" << std::endl;
++num_events;
}
};
boost::asio::spawn(io_service, std::move(waiter));
boost::thread thread(boost::bind(&boost::asio::io_service::run, &io_service));
for (auto i = 0; i < 5000; ++i) {
io_service.post([&timer, i]{
std::cout << i << std::endl;
timer.cancel();
});
}
io_service.post([&]{
shutdown = true;
timer.cancel();
});
thread.join();
std::cout << "Check: " << num_events << " events counted\n";
}
此外,您似乎只想发出后台任务信号.如您所述,您可以简化程序,如:
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
using boost::thread;
using boost::asio::io_service;
int main() {
io_service svc;
int num_events = 0;
auto work = boost::make_shared<io_service::work>(svc); // keep svc running
boost::thread thread(boost::bind(&io_service::run, &svc));
for (auto i = 0; i < 500000; ++i) {
svc.post([&num_events,i]{
std::cout << "got event (" << i << ")" << std::endl;
++num_events;
});
}
work.reset();
thread.join();
std::cout << "Check: " << num_events << " events counted\n";
}
这会打印所有500000个事件:
got event (0)
got event (1)
got event (3)
...
got event (499998)
got event (499999)
Check: 500000 events counted