I would like to be able to do asynchronous waiting for a specific event. There are many similar questions and answers here (and they all compile and work for me), but none of them have my specific scenario. Basically, I need to do this async_wait, passing the yield context as a handler, to a timer that waits indefinitely, and then is canceled by another thread.
For example, there is this question that does something very similar, but instead of using the profitability context, it uses a separate standalone handler. There is also something like this question that uses the yield context, but waits for a certain amount of time.
I can change my code to look like one of the two examples above, and everything works fine. But for some reason, when I combine the yield_context handler and the canceled timer, I get the following exception:
libc++abi.dylib: terminating with uncaught exception of type boost::exception_detail::clone_impl<boost::exception_detail::current_exception_std_exception_wrapper<std::runtime_error> >:
Program ended with exit code: 9
From what I can say, it looks like when you try to call the completion handler (which in this case is the yield context), a throttle occurs.
Ok, stop talking, here is the code. I tried to come up with as simple an example as possible to illustrate this:
Grade:
class Foo {
public:
Foo() : work_(io_service_), timer_(io_service_) {
thread_pool_.create_thread(boost::bind(&boost::asio::io_service::run, &io_service_));
timer_.expires_from_now(boost::posix_time::pos_infin);
}
~Foo() {
io_service_.stop();
thread_pool_.join_all();
}
void Wait(const boost::asio::yield_context& context) {
std::cout << "Waiting" << std::endl;
timer_.async_wait(context);
std::cout << "Done waiting" << std::endl;
}
void Notify() {
std::cout << "Notifying" << std::endl;
timer_.cancel();
}
void Write(int num) {
std::cout << "Sending buffer event" << std::endl;
Notify();
std::cout << "Sent buffer event" << std::endl;
}
void Read(const boost::asio::yield_context& context) {
std::cout << "Waiting on buffer event, size is " << buffer_.size() << std::endl;
Wait(context);
std::cout << "Received buffer event, size is now " << buffer_.size() << std::endl;
}
std::vector<int> buffer_;
boost::asio::io_service io_service_;
boost::thread_group thread_pool_;
boost::asio::io_service::work work_;
boost::asio::deadline_timer timer_;
};
Main:
boost::shared_ptr<Foo> foo(new Foo());
boost::asio::spawn(foo->io_service_, boost::bind(&Foo::Read, foo, _1));
boost::this_thread::sleep(boost::posix_time::seconds(2));
foo->Write(1);
boost::this_thread::sleep(boost::posix_time::seconds(4));
Conclusion:
Waiting on buffer event
Waiting
Sending buffer event
Notifying
Sent buffer event
libc++abi.dylib: terminating with uncaught exception of type boost::exception_detail::clone_impl<boost::exception_detail::current_exception_std_exception_wrapper<std::runtime_error> >:
, wait , - cancel, . :.
void Wait(const boost::asio::yield_context& context) {
std::cout << "Waiting" << std::endl;
timer_.expires_from_now(boost::posix_time::seconds(1));
timer_.async_wait(context);
std::cout << "Done waiting" << std::endl;
}
, , . :.
void Handler() {
std::cout << "Handler!" << std::endl;
}
void Wait(const boost::asio::yield_context& context) {
std::cout << "Waiting" << std::endl;
timer_.async_wait(boost::bind(&Foo::Handler, this));
std::cout << "Done waiting" << std::endl;
}
, - , : - , . , .