boost::asio::d eadline_timer 不会唤醒(压力场景)
boost::asio::deadline_timer doesn't wake up (stress scenario)
我正在使用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()
的错误代码看起来从来都不麻烦(即使是在它最后一次被唤醒时,它似乎再也不会被唤醒)。编辑:我也注意到了三个不同平台(Windows、Mac和Linux)上的原始错误,但我用来复制的上述测试是在Windows上进行的。
deadline_timer对象不是线程安全的。
您正在从发布async_wait的线程之外的另一个线程取消它。这意味着呼叫可能会竞争。
在您的示例中,我不确定这是如何完全抑制回调的。在我看来,程序应该/just/quit,因为到500000的紧密循环很快就完成了(做了许多从未处理过的冗余取消,因为协程甚至没有发布新的async_wait)。
所以,也许你的意思是,"为什么我不举办50万场活动"。
更新
在评论之后,这里有一个琐碎的转换,它显示了如何从actor内部调用计时器上的成员。注意:这主要取决于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 countedn";
}
此外,看起来你只是想发出一个后台任务的信号。如给定,您可以简化程序,如:
查看Coliru直播
#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 countedn";
}
此将打印所有500000个事件:
got event (0)
got event (1)
got event (3)
...
got event (499998)
got event (499999)
Check: 500000 events counted
相关文章:
- 虚假唤醒是否会解锁所有等待线程,甚至是不相关的线程?
- 是否有必要获取锁并在不需要唤醒线程时通知condition_variable?
- 如果我们使用 notify_one() 来唤醒线程,我们还需要 yield() - C++?
- 避免在条件更新时丢失唤醒是一个阻塞功能
- 升压插值条件变量可以虚假唤醒吗?
- 唤醒多个线程以在每个条件下工作一次
- 视频在唤醒其他线程时输入设备断开连接
- 线程启动延迟 - 通知所有未唤醒所有线程
- 使用set_alert_notify唤醒主线程的正确方法是什么?
- pthread 互斥锁 - 是定期检查还是操作系统唤醒它
- 在离开模式下唤醒窗户
- 使用 Poco:Condition 唤醒两个线程
- Futex等待/唤醒对实现获取/发布语义吗?
- std::condition_variable::notify_one() 不会唤醒等待线程
- absl::Mutex 的条件关键部分如何处理读取器唤醒
- 如何检测Windows服务中的睡眠模式唤醒
- 唤醒线程很耗时
- 如何从父级C 发送给孩子的唤醒信号
- Arduino压力传感器在旋律C 中跳过音符
- boost::asio::d eadline_timer 不会唤醒(压力场景)