// // prioritised_handlers.cpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include #include #include #include using boost::asio::ip::tcp; class handler_priority_queue { public: void add(int priority, boost::function function) { handlers_.push(queued_handler(priority, function)); } void execute_all() { while (!handlers_.empty()) { queued_handler handler = handlers_.top(); handler.execute(); handlers_.pop(); } } // A generic wrapper class for handlers to allow the invocation to be hooked. template class wrapped_handler { public: wrapped_handler(handler_priority_queue& q, int p, Handler h) : queue_(q), priority_(p), handler_(h) { } void operator()() { handler_(); } template void operator()(Arg1 arg1) { handler_(arg1); } template void operator()(Arg1 arg1, Arg2 arg2) { handler_(arg1, arg2); } //private: handler_priority_queue& queue_; int priority_; Handler handler_; }; template wrapped_handler wrap(int priority, Handler handler) { return wrapped_handler(*this, priority, handler); } private: class queued_handler { public: queued_handler(int p, boost::function f) : priority_(p), function_(f) { } void execute() { function_(); } friend bool operator<(const queued_handler& a, const queued_handler& b) { return a.priority_ < b.priority_; } private: int priority_; boost::function function_; }; std::priority_queue handlers_; }; // Custom invocation hook for wrapped handlers. template void asio_handler_invoke(Function f, handler_priority_queue::wrapped_handler* h) { h->queue_.add(h->priority_, f); } //---------------------------------------------------------------------- void high_priority_handler(const boost::system::error_code& /*ec*/) { std::cout << "High priority handler\n"; } void middle_priority_handler(const boost::system::error_code& /*ec*/) { std::cout << "Middle priority handler\n"; } void low_priority_handler() { std::cout << "Low priority handler\n"; } int main() { boost::asio::io_service io_service; handler_priority_queue pri_queue; // Post a completion handler to be run immediately. io_service.post(pri_queue.wrap(0, low_priority_handler)); // Start an asynchronous accept that will complete immediately. tcp::endpoint endpoint(boost::asio::ip::address_v4::loopback(), 0); tcp::acceptor acceptor(io_service, endpoint); tcp::socket server_socket(io_service); acceptor.async_accept(server_socket, pri_queue.wrap(100, high_priority_handler)); tcp::socket client_socket(io_service); client_socket.connect(acceptor.local_endpoint()); // Set a deadline timer to expire immediately. boost::asio::deadline_timer timer(io_service); timer.expires_at(boost::posix_time::neg_infin); timer.async_wait(pri_queue.wrap(42, middle_priority_handler)); while (io_service.run_one()) { // The custom invocation hook adds the handlers to the priority queue // rather than executing them from within the poll_one() call. while (io_service.poll_one()) ; pri_queue.execute_all(); } return 0; }