2 // prioritised_handlers.cpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 #include <boost/asio.hpp>
16 using boost::asio::ip::tcp
;
18 class handler_priority_queue
: boost::asio::execution_context
21 template <typename Function
>
22 void add(int priority
, Function function
)
24 std::unique_ptr
<queued_handler_base
> handler(
25 new queued_handler
<Function
>(
26 priority
, std::move(function
)));
28 handlers_
.push(std::move(handler
));
33 while (!handlers_
.empty())
35 handlers_
.top()->execute();
43 executor(handler_priority_queue
& q
, int p
)
44 : context_(q
), priority_(p
)
48 handler_priority_queue
& context() const noexcept
53 template <typename Function
, typename Allocator
>
54 void dispatch(Function f
, const Allocator
&) const
56 context_
.add(priority_
, std::move(f
));
59 template <typename Function
, typename Allocator
>
60 void post(Function f
, const Allocator
&) const
62 context_
.add(priority_
, std::move(f
));
65 template <typename Function
, typename Allocator
>
66 void defer(Function f
, const Allocator
&) const
68 context_
.add(priority_
, std::move(f
));
71 void on_work_started() const noexcept
{}
72 void on_work_finished() const noexcept
{}
74 bool operator==(const executor
& other
) const noexcept
76 return &context_
== &other
.context_
&& priority_
== other
.priority_
;
79 bool operator!=(const executor
& other
) const noexcept
81 return !operator==(other
);
85 handler_priority_queue
& context_
;
89 template <typename Handler
>
90 boost::asio::executor_binder
<Handler
, executor
>
91 wrap(int priority
, Handler handler
)
93 return boost::asio::bind_executor(
94 executor(*this, priority
), std::move(handler
));
98 class queued_handler_base
101 queued_handler_base(int p
)
106 virtual ~queued_handler_base()
110 virtual void execute() = 0;
112 friend bool operator<(const std::unique_ptr
<queued_handler_base
>& a
,
113 const std::unique_ptr
<queued_handler_base
>& b
) noexcept
115 return a
->priority_
< b
->priority_
;
122 template <typename Function
>
123 class queued_handler
: public queued_handler_base
126 queued_handler(int p
, Function f
)
127 : queued_handler_base(p
), function_(std::move(f
))
131 void execute() override
140 std::priority_queue
<std::unique_ptr
<queued_handler_base
>> handlers_
;
143 //----------------------------------------------------------------------
145 void high_priority_handler(const boost::system::error_code
& /*ec*/)
147 std::cout
<< "High priority handler\n";
150 void middle_priority_handler(const boost::system::error_code
& /*ec*/)
152 std::cout
<< "Middle priority handler\n";
155 struct low_priority_handler
157 // Make the handler a move-only type.
158 low_priority_handler() = default;
159 low_priority_handler(const low_priority_handler
&) = delete;
160 low_priority_handler(low_priority_handler
&&) = default;
164 std::cout
<< "Low priority handler\n";
170 boost::asio::io_context io_context
;
172 handler_priority_queue pri_queue
;
174 // Post a completion handler to be run immediately.
175 boost::asio::post(io_context
, pri_queue
.wrap(0, low_priority_handler()));
177 // Start an asynchronous accept that will complete immediately.
178 tcp::endpoint
endpoint(boost::asio::ip::address_v4::loopback(), 0);
179 tcp::acceptor
acceptor(io_context
, endpoint
);
180 tcp::socket
server_socket(io_context
);
181 acceptor
.async_accept(server_socket
,
182 pri_queue
.wrap(100, high_priority_handler
));
183 tcp::socket
client_socket(io_context
);
184 client_socket
.connect(acceptor
.local_endpoint());
186 // Set a deadline timer to expire immediately.
187 boost::asio::steady_timer
timer(io_context
);
188 timer
.expires_at(boost::asio::steady_timer::clock_type::time_point::min());
189 timer
.async_wait(pri_queue
.wrap(42, middle_priority_handler
));
191 while (io_context
.run_one())
193 // The custom invocation hook adds the handlers to the priority queue
194 // rather than executing them from within the poll_one() call.
195 while (io_context
.poll_one())
198 pri_queue
.execute_all();