src/examples/cpp03/invocation/prioritised_handlers.cpp | src/examples/cpp11/invocation/prioritised_handlers.cpp |
⋮ | ⋮ |
1 | // | 1 | // |
2 | //·prioritised_handlers.cpp | 2 | //·prioritised_handlers.cpp |
3 | //·~~~~~~~~~~~~~~~~~~~~~~~~ | 3 | //·~~~~~~~~~~~~~~~~~~~~~~~~ |
4 | // | 4 | // |
5 | //·Copyright·(c)·2003-2023·Christopher·M.·Kohlhoff·(chris·at·kohlhoff·dot·com) | 5 | //·Copyright·(c)·2003-2023·Christopher·M.·Kohlhoff·(chris·at·kohlhoff·dot·com) |
6 | // | 6 | // |
7 | //·Distributed·under·the·Boost·Software·License,·Version·1.0.·(See·accompanying | 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) | 8 | //·file·LICENSE_1_0.txt·or·copy·at·http://www.boost.org/LICENSE_1_0.txt) |
9 | // | 9 | // |
10 | | 10 | |
11 | #include·"asio.hpp" | 11 | #include·"asio.hpp" |
12 | #include·<boost/function.hpp> | |
13 | #include·<iostream> | 12 | #include·<iostream> |
| 13 | #include·<memory> |
14 | #include·<queue> | 14 | #include·<queue> |
15 | | 15 | |
16 | using·asio::ip::tcp; | 16 | using·asio::ip::tcp; |
17 | | 17 | |
18 | class·handler_priority_queue·:·public·asio::execution_context | 18 | class·handler_priority_queue·:·public·asio::execution_context |
19 | { | 19 | { |
20 | public: | 20 | public: |
21 | ··void·add(int·priority,·boost::function<void()>·function) | 21 | ··template·<typename·Function> |
| 22 | ··void·add(int·priority,·Function·function) |
22 | ··{ | 23 | ··{ |
23 | ····handlers_.push(queued_handler(priority,·function)); | 24 | ····std::unique_ptr<queued_handler_base>·handler( |
| 25 | ········new·queued_handler<Function>( |
| 26 | ··········priority,·std::move(function))); |
| 27 | |
| 28 | ····handlers_.push(std::move(handler)); |
24 | ··} | 29 | ··} |
25 | | 30 | |
26 | ··void·execute_all() | 31 | ··void·execute_all() |
27 | ··{ | 32 | ··{ |
28 | ····while·(!handlers_.empty()) | 33 | ····while·(!handlers_.empty()) |
29 | ····{ | 34 | ····{ |
30 | ······queued_handler·handler·=·handlers_.top(); | 35 | ······handlers_.top()->execute(); |
31 | ······handler.execute(); | |
32 | ······handlers_.pop(); | 36 | ······handlers_.pop(); |
33 | ····} | 37 | ····} |
34 | ··} | 38 | ··} |
35 | | 39 | |
36 | ··class·executor | 40 | ··class·executor |
37 | ··{ | 41 | ··{ |
38 | ··public: | 42 | ··public: |
39 | ····executor(handler_priority_queue&·q,·int·p) | 43 | ····executor(handler_priority_queue&·q,·int·p) |
40 | ······:·context_(q),·priority_(p) | 44 | ······:·context_(q),·priority_(p) |
41 | ····{ | 45 | ····{ |
42 | ····} | 46 | ····} |
43 | | 47 | |
44 | ····handler_priority_queue&·context()·const | 48 | ····handler_priority_queue&·context()·const·noexcept |
45 | ····{ | 49 | ····{ |
46 | ······return·context_; | 50 | ······return·context_; |
47 | ····} | 51 | ····} |
48 | | 52 | |
49 | ····template·<typename·Function,·typename·Allocator> | 53 | ····template·<typename·Function,·typename·Allocator> |
50 | ····void·dispatch(const·Function&·f,·const·Allocator&)·const | 54 | ····void·dispatch(Function·f,·const·Allocator&)·const |
51 | ····{ | 55 | ····{ |
52 | ······context_.add(priority_,·f); | 56 | ······context_.add(priority_,·std::move(f)); |
53 | ····} | 57 | ····} |
54 | | 58 | |
55 | ····template·<typename·Function,·typename·Allocator> | 59 | ····template·<typename·Function,·typename·Allocator> |
56 | ····void·post(const·Function&·f,·const·Allocator&)·const | 60 | ····void·post(Function·f,·const·Allocator&)·const |
57 | ····{ | 61 | ····{ |
58 | ······context_.add(priority_,·f); | 62 | ······context_.add(priority_,·std::move(f)); |
59 | ····} | 63 | ····} |
60 | | 64 | |
61 | ····template·<typename·Function,·typename·Allocator> | 65 | ····template·<typename·Function,·typename·Allocator> |
62 | ····void·defer(const·Function&·f,·const·Allocator&)·const | 66 | ····void·defer(Function·f,·const·Allocator&)·const |
63 | ····{ | 67 | ····{ |
64 | ······context_.add(priority_,·f); | 68 | ······context_.add(priority_,·std::move(f)); |
65 | ····} | 69 | ····} |
66 | | 70 | |
67 | ····void·on_work_started()·const·{} | 71 | ····void·on_work_started()·const·noexcept·{} |
68 | ····void·on_work_finished()·const·{} | 72 | ····void·on_work_finished()·const·noexcept·{} |
69 | | 73 | |
70 | ····bool·operator==(const·executor&·other)·const | 74 | ····bool·operator==(const·executor&·other)·const·noexcept |
71 | ····{ | 75 | ····{ |
72 | ······return·&context_·==·&other.context_·&&·priority_·==·other.priority_; | 76 | ······return·&context_·==·&other.context_·&&·priority_·==·other.priority_; |
73 | ····} | 77 | ····} |
74 | | 78 | |
75 | ····bool·operator!=(const·executor&·other)·const | 79 | ····bool·operator!=(const·executor&·other)·const·noexcept |
76 | ····{ | 80 | ····{ |
77 | ······return·!operator==(other); | 81 | ······return·!operator==(other); |
78 | ····} | 82 | ····} |
79 | | 83 | |
80 | ··private: | 84 | ··private: |
81 | ····handler_priority_queue&·context_; | 85 | ····handler_priority_queue&·context_; |
82 | ····int·priority_; | 86 | ····int·priority_; |
83 | ··}; | 87 | ··}; |
84 | | 88 | |
85 | ··template·<typename·Handler> | 89 | ··template·<typename·Handler> |
86 | ··asio::executor_binder<Handler,·executor> | 90 | ··asio::executor_binder<Handler,·executor> |
87 | ··wrap(int·priority,·Handler·handler) | 91 | ··wrap(int·priority,·Handler·handler) |
88 | ··{ | 92 | ··{ |
89 | ····return·asio::bind_executor(executor(*this,·priority),·handler); | 93 | ····return·asio::bind_executor( |
| 94 | ········executor(*this,·priority),·std::move(handler)); |
90 | ··} | 95 | ··} |
91 | | 96 | |
92 | private: | 97 | private: |
93 | ··class·queued_handler | 98 | ··class·queued_handler_base |
94 | ··{ | 99 | ··{ |
95 | ··public: | 100 | ··public: |
96 | ····queued_handler(int·p,·boost::function<void()>·f) | 101 | ····queued_handler_base(int·p) |
97 | ······:·priority_(p),·function_(f) | 102 | ······:·priority_(p) |
98 | ····{ | 103 | ····{ |
99 | ····} | 104 | ····} |
100 | | 105 | |
101 | ····void·execute() | 106 | ····virtual·~queued_handler_base() |
102 | ····{ | 107 | ····{ |
103 | ······function_(); | |
104 | ····} | 108 | ····} |
105 | | 109 | |
106 | ····friend·bool·operator<(const·queued_handler&·a, | 110 | ····virtual·void·execute()·=·0; |
107 | ········const·queued_handler&·b) | 111 | |
| 112 | ····friend·bool·operator<(const·std::unique_ptr<queued_handler_base>&·a, |
| 113 | ········const·std::unique_ptr<queued_handler_base>&·b)·noexcept |
108 | ····{ | 114 | ····{ |
109 | ······return·a.priority_·<·b.priority_; | 115 | ······return·a->priority_·<·b->priority_; |
110 | ····} | 116 | ····} |
111 | | 117 | |
112 | ··private: | 118 | ··private: |
113 | ····int·priority_; | 119 | ····int·priority_; |
114 | ····boost::function<void()>·function_; | |
115 | ··}; | 120 | ··}; |
116 | | 121 | |
117 | ··std::priority_queue<queued_handler>·handlers_; | 122 | ··template·<typename·Function> |
| 123 | ··class·queued_handler·:·public·queued_handler_base |
| 124 | ··{ |
| 125 | ··public: |
| 126 | ····queued_handler(int·p,·Function·f) |
| 127 | ······:·queued_handler_base(p),·function_(std::move(f)) |
| 128 | ····{ |
| 129 | ····} |
| 130 | |
| 131 | ····void·execute()·override |
| 132 | ····{ |
| 133 | ······function_(); |
| 134 | ····} |
| 135 | |
| 136 | ··private: |
| 137 | ····Function·function_; |
| 138 | ··}; |
| 139 | |
| 140 | ··std::priority_queue<std::unique_ptr<queued_handler_base>>·handlers_; |
118 | }; | 141 | }; |
119 | | 142 | |
120 | //---------------------------------------------------------------------- | 143 | //---------------------------------------------------------------------- |
121 | | 144 | |
122 | void·high_priority_handler(const·asio::error_code&·/*ec*/) | 145 | void·high_priority_handler(const·asio::error_code&·/*ec*/, |
| 146 | ····tcp::socket·/*socket*/) |
123 | { | 147 | { |
124 | ··std::cout·<<·"High·priority·handler\n"; | 148 | ··std::cout·<<·"High·priority·handler\n"; |
125 | } | 149 | } |
126 | | 150 | |
127 | void·middle_priority_handler(const·asio::error_code&·/*ec*/) | 151 | void·middle_priority_handler(const·asio::error_code&·/*ec*/) |
128 | { | 152 | { |
129 | ··std::cout·<<·"Middle·priority·handler\n"; | 153 | ··std::cout·<<·"Middle·priority·handler\n"; |
130 | } | 154 | } |
131 | | 155 | |
132 | void·low_priority_handler() | 156 | struct·low_priority_handler |
133 | { | 157 | { |
134 | ··std::cout·<<·"Low·priority·handler\n"; | 158 | ··//·Make·the·handler·a·move-only·type. |
135 | } | 159 | ··low_priority_handler()·=·default; |
| 160 | ··low_priority_handler(const·low_priority_handler&)·=·delete; |
| 161 | ··low_priority_handler(low_priority_handler&&)·=·default; |
136 | | 162 | |
| 163 | ··void·operator()() |
| 164 | ··{ |
| 165 | ····std::cout·<<·"Low·priority·handler\n"; |
| 166 | ··} |
| 167 | }; |
| 168 | |
137 | int·main() | 169 | int·main() |
138 | { | 170 | { |
139 | ··asio::io_context·io_context; | 171 | ··asio::io_context·io_context; |
140 | | 172 | |
141 | ··handler_priority_queue·pri_queue; | 173 | ··handler_priority_queue·pri_queue; |
142 | | 174 | |
143 | ··//·Post·a·completion·handler·to·be·run·immediately. | 175 | ··//·Post·a·completion·handler·to·be·run·immediately. |
144 | ··asio::post(io_context,·pri_queue.wrap(0,·low_priority_handler)); | 176 | ··asio::post(io_context,·pri_queue.wrap(0,·low_priority_handler())); |
145 | | 177 | |
146 | ··//·Start·an·asynchronous·accept·that·will·complete·immediately. | 178 | ··//·Start·an·asynchronous·accept·that·will·complete·immediately. |
147 | ··tcp::endpoint·endpoint(asio::ip::address_v4::loopback(),·0); | 179 | ··tcp::endpoint·endpoint(asio::ip::address_v4::loopback(),·0); |
148 | ··tcp::acceptor·acceptor(io_context,·endpoint); | 180 | ··tcp::acceptor·acceptor(io_context,·endpoint); |
149 | ··tcp::socket·server_socket(io_context); | 181 | ··tcp::socket·server_socket(io_context); |
150 | ··acceptor.async_accept(server_socket, | 182 | ··acceptor.async_accept(pri_queue.wrap(100,·high_priority_handler)); |
151 | ······pri_queue.wrap(100,·high_priority_handler)); | |
152 | ··tcp::socket·client_socket(io_context); | 183 | ··tcp::socket·client_socket(io_context); |
153 | ··client_socket.connect(acceptor.local_endpoint()); | 184 | ··client_socket.connect(acceptor.local_endpoint()); |
154 | | 185 | |
155 | ··//·Set·a·deadline·timer·to·expire·immediately. | 186 | ··//·Set·a·deadline·timer·to·expire·immediately. |
156 | ··asio::steady_timer·timer(io_context); | 187 | ··asio::steady_timer·timer(io_context); |
157 | ··timer.expires_at(asio::steady_timer::time_point::min()); | 188 | ··timer.expires_at(asio::steady_timer::clock_type::time_point::min()); |
158 | ··timer.async_wait(pri_queue.wrap(42,·middle_priority_handler)); | 189 | ··timer.async_wait(pri_queue.wrap(42,·middle_priority_handler)); |
159 | | 190 | |
160 | ··while·(io_context.run_one()) | 191 | ··while·(io_context.run_one()) |
161 | ··{ | 192 | ··{ |
162 | ····//·The·custom·invocation·hook·adds·the·handlers·to·the·priority·queue | 193 | ····//·The·custom·invocation·hook·adds·the·handlers·to·the·priority·queue |
163 | ····//·rather·than·executing·them·from·within·the·poll_one()·call. | 194 | ····//·rather·than·executing·them·from·within·the·poll_one()·call. |
164 | ····while·(io_context.poll_one()) | 195 | ····while·(io_context.poll_one()) |
165 | ······; | 196 | ······; |
166 | | 197 | |
167 | ····pri_queue.execute_all(); | 198 | ····pri_queue.execute_all(); |
168 | ··} | 199 | ··} |
169 | | 200 | |
170 | ··return·0; | 201 | ··return·0; |
171 | } | 202 | } |