| // |
| // prioritised_handlers.cpp |
| // ~~~~~~~~~~~~~~~~~~~~~~~~ |
| // |
| // Copyright (c) 2003-2021 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 "asio.hpp" |
| #include <boost/function.hpp> |
| #include <iostream> |
| #include <queue> |
| |
| using asio::ip::tcp; |
| |
| class handler_priority_queue : public asio::execution_context |
| { |
| public: |
| void add(int priority, boost::function<void()> function) |
| { |
| handlers_.push(queued_handler(priority, function)); |
| } |
| |
| void execute_all() |
| { |
| while (!handlers_.empty()) |
| { |
| queued_handler handler = handlers_.top(); |
| handler.execute(); |
| handlers_.pop(); |
| } |
| } |
| |
| class executor |
| { |
| public: |
| executor(handler_priority_queue& q, int p) |
| : context_(q), priority_(p) |
| { |
| } |
| |
| handler_priority_queue& context() const |
| { |
| return context_; |
| } |
| |
| template <typename Function, typename Allocator> |
| void dispatch(const Function& f, const Allocator&) const |
| { |
| context_.add(priority_, f); |
| } |
| |
| template <typename Function, typename Allocator> |
| void post(const Function& f, const Allocator&) const |
| { |
| context_.add(priority_, f); |
| } |
| |
| template <typename Function, typename Allocator> |
| void defer(const Function& f, const Allocator&) const |
| { |
| context_.add(priority_, f); |
| } |
| |
| void on_work_started() const {} |
| void on_work_finished() const {} |
| |
| bool operator==(const executor& other) const |
| { |
| return &context_ == &other.context_ && priority_ == other.priority_; |
| } |
| |
| bool operator!=(const executor& other) const |
| { |
| return !operator==(other); |
| } |
| |
| private: |
| handler_priority_queue& context_; |
| int priority_; |
| }; |
| |
| template <typename Handler> |
| asio::executor_binder<Handler, executor> |
| wrap(int priority, Handler handler) |
| { |
| return asio::bind_executor(executor(*this, priority), handler); |
| } |
| |
| private: |
| class queued_handler |
| { |
| public: |
| queued_handler(int p, boost::function<void()> 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<void()> function_; |
| }; |
| |
| std::priority_queue<queued_handler> handlers_; |
| }; |
| |
| //---------------------------------------------------------------------- |
| |
| void high_priority_handler(const asio::error_code& /*ec*/) |
| { |
| std::cout << "High priority handler\n"; |
| } |
| |
| void middle_priority_handler(const asio::error_code& /*ec*/) |
| { |
| std::cout << "Middle priority handler\n"; |
| } |
| |
| void low_priority_handler() |
| { |
| std::cout << "Low priority handler\n"; |
| } |
| |
| int main() |
| { |
| asio::io_context io_context; |
| |
| handler_priority_queue pri_queue; |
| |
| // Post a completion handler to be run immediately. |
| asio::post(io_context, pri_queue.wrap(0, low_priority_handler)); |
| |
| // Start an asynchronous accept that will complete immediately. |
| tcp::endpoint endpoint(asio::ip::address_v4::loopback(), 0); |
| tcp::acceptor acceptor(io_context, endpoint); |
| tcp::socket server_socket(io_context); |
| acceptor.async_accept(server_socket, |
| pri_queue.wrap(100, high_priority_handler)); |
| tcp::socket client_socket(io_context); |
| client_socket.connect(acceptor.local_endpoint()); |
| |
| // Set a deadline timer to expire immediately. |
| asio::steady_timer timer(io_context); |
| timer.expires_at(asio::steady_timer::time_point::min()); |
| timer.async_wait(pri_queue.wrap(42, middle_priority_handler)); |
| |
| while (io_context.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_context.poll_one()) |
| ; |
| |
| pri_queue.execute_all(); |
| } |
| |
| return 0; |
| } |