我正在使用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上进行。
答案 0 :(得分:2)
deadline_timer对象不是线程安全的。
你要从另一个帖子取消它而不是发布async_wait的帖子。这意味着通话可以比赛。
我不确定这样可以完全抑制样本中的回调。在我看来,该程序应该/只是/退出,因为500000的紧密循环很快完成(执行许多永远不会被处理的冗余取消,因为例程甚至没有发布新的async_wait)。
所以也许你的意思是,“为什么我不能获得500000个活动”。
评论之后,这是一个微不足道的转变,显示你如何在演员中调用计时器上的成员。注意:这关键取决于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