]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [/ |
2 | Copyright Oliver Kowalke 2013. | |
3 | Distributed under the Boost Software License, Version 1.0. | |
4 | (See accompanying file LICENSE_1_0.txt or copy at | |
5 | http://www.boost.org/LICENSE_1_0.txt | |
6 | ] | |
7 | ||
8 | [section:channels Channels] | |
9 | ||
10 | __boost_fiber__ provides a bounded and a unbounded channel suitable to | |
11 | synchonize fibers via message passing. | |
12 | ||
13 | typedef boost::fibers::unbounded_channel< int > channel_t; | |
14 | ||
15 | void send( channel_t & channel) { | |
16 | for ( int i = 0; i < 5; ++i) { | |
17 | channel.push( i); | |
18 | } | |
19 | channel.close(); | |
20 | } | |
21 | ||
22 | void recv( channel_t & channel) { | |
23 | int i; | |
24 | while ( boost::fibers::channel_op_status::success == channel.pop(i) ) { | |
25 | std::cout << "received " << i << std::endl; | |
26 | } | |
27 | } | |
28 | ||
29 | channel_t channel; | |
30 | boost::fibers::fiber f1( std::bind( send, ref( channel) ) ); | |
31 | boost::fibers::fiber f2( std::bind( recv, ref( channel) ) ); | |
32 | ||
33 | f1.join(); | |
34 | f2.join(); | |
35 | ||
36 | [#class_channel_op_status] | |
37 | [heading Enumeration `channel_op_status`] | |
38 | ||
39 | channel operations return the state of the channel. | |
40 | ||
41 | enum class channel_op_status { | |
42 | success, | |
43 | empty, | |
44 | full, | |
45 | closed, | |
46 | timeout | |
47 | }; | |
48 | ||
49 | [heading `success`] | |
50 | [variablelist | |
51 | [[Effects:] [Operation was successful.]] | |
52 | ] | |
53 | ||
54 | [heading `empty`] | |
55 | [variablelist | |
56 | [[Effects:] [channel is empty, operation failed.]] | |
57 | ] | |
58 | ||
59 | [heading `full`] | |
60 | [variablelist | |
61 | [[Effects:] [channel is full, operation failed.]] | |
62 | ] | |
63 | ||
64 | [heading `closed`] | |
65 | [variablelist | |
66 | [[Effects:] [channel is closed, operation failed.]] | |
67 | ] | |
68 | ||
69 | [heading `timeout`] | |
70 | [variablelist | |
71 | [[Effects:] [The operation did not become ready before specified timeout elapsed.]] | |
72 | ] | |
73 | ||
74 | [template_heading unbounded_channel] | |
75 | ||
76 | #include <boost/fiber/unbounded_channel.hpp> | |
77 | ||
78 | namespace boost { | |
79 | namespace fibers { | |
80 | ||
81 | template< typename T, typename __Allocator__ = __allocator__ > | |
82 | class unbounded_channel { | |
83 | public: | |
84 | typedef T value_type; | |
85 | ||
86 | explicit unbounded_channel( __Allocator__ const& alloc = Allocator() ) noexcept; | |
87 | ||
88 | unbounded_channel( unbounded_channel const& other) = delete; | |
89 | unbounded_channel & operator=( unbounded_channel const& other) = delete; | |
90 | ||
91 | void close() noexcept; | |
92 | ||
93 | channel_op_status push( value_type const& va); | |
94 | channel_op_status push( value_type && va); | |
95 | ||
96 | channel_op_status pop( value_type & va); | |
97 | value_type value_pop(); | |
98 | channel_op_status try_pop( value_type & va); | |
99 | template< typename Rep, typename Period > | |
100 | channel_op_status pop_wait_for( | |
101 | value_type & va, | |
102 | std::chrono::duration< Rep, Period > const& timeout_duration); | |
103 | template< typename Clock, typename Duration > | |
104 | channel_op_status pop_wait_until( | |
105 | value_type & va, | |
106 | std::chrono::time_point< Clock, Duration > const& timeout_time); | |
107 | }; | |
108 | ||
109 | }} | |
110 | ||
111 | [heading Constructor] | |
112 | ||
113 | explicit unbounded_channel( __Allocator__ const& alloc = Allocator() ) noexcept; | |
114 | ||
115 | [variablelist | |
116 | [[Effects:] [Constructs an object of class `unbounded_channel`. | |
117 | Internal nodes are allocated using `alloc` - C++11-allocators are supported.]] | |
118 | [[Throws:] [Nothing.]] | |
119 | [[See also:] [__Allocator__ concept, __allocator__]] | |
120 | ] | |
121 | ||
122 | [template xchannel_close[cls] | |
123 | [member_heading [cls]..close] | |
124 | ||
125 | void close() noexcept; | |
126 | ||
127 | [variablelist | |
128 | [[Effects:] [Deactivates the channel. No values can be put after calling | |
129 | `this->close()`. Fibers blocked in `this->pop()`, `this->pop_wait_for()` | |
130 | or `this->pop_wait_until()` will return `closed`. Fibers blocked in | |
131 | `this->value_pop()` will receive an exception.]] | |
132 | [[Throws:] [Nothing.]] | |
133 | [[Note:] [`close()` is like closing a pipe. It informs waiting consumers | |
134 | that no more values will arrive.]] | |
135 | ] | |
136 | ] | |
137 | [xchannel_close unbounded_channel] | |
138 | ||
139 | [template xchannel_push_effects[enqueues] If channel is closed, returns | |
140 | `closed`. [enqueues] the value in the channel, wakes up a fiber | |
141 | blocked on `this->pop()`, `this->value_pop()`, `this->pop_wait_for()` or | |
142 | `this->pop_wait_until()` and returns `success`.] | |
143 | ||
144 | [member_heading unbounded_channel..push] | |
145 | ||
146 | channel_op_status push( value_type const& va); | |
147 | channel_op_status push( value_type && va); | |
148 | ||
149 | [variablelist | |
150 | [[Effects:] [[xchannel_push_effects Otherwise enqueues]]] | |
151 | [[Throws:] [Exceptions thrown by memory allocation and copying or moving | |
152 | `va`.]] | |
153 | ] | |
154 | ||
155 | [template xchannel_pop[cls unblocking] | |
156 | [member_heading [cls]..pop] | |
157 | ||
158 | channel_op_status pop( value_type & va); | |
159 | ||
160 | [variablelist | |
161 | [[Effects:] [Dequeues a value from the channel. If the channel is empty, the | |
162 | fiber gets suspended until at least one new item is `push()`ed (return value | |
163 | `success` and `va` contains dequeued value) or the channel gets `close()`d | |
164 | (return value `closed`)[unblocking]]] | |
165 | [[Throws:] [Nothing]] | |
166 | ] | |
167 | ] | |
168 | [xchannel_pop unbounded_channel .] | |
169 | ||
170 | [template xchannel_value_pop[cls unblocking] | |
171 | [member_heading [cls]..value_pop] | |
172 | ||
173 | value_type value_pop(); | |
174 | ||
175 | [variablelist | |
176 | [[Effects:] [Dequeues a value from the channel. If the channel is empty, the | |
177 | fiber gets suspended until at least one new item is `push()`ed or the channel | |
178 | gets `close()`d (which throws an exception)[unblocking]]] | |
179 | [[Throws:] [`fiber_error` if `*this` is closed]] | |
180 | [[Error conditions:] [`std::errc::operation_not_permitted`]] | |
181 | ] | |
182 | ] | |
183 | [xchannel_value_pop unbounded_channel .] | |
184 | ||
185 | [template xchannel_try_pop[cls unblocking] | |
186 | [member_heading [cls]..try_pop] | |
187 | ||
188 | channel_op_status try_pop( value_type & va); | |
189 | ||
190 | [variablelist | |
191 | [[Effects:] [If channel is empty, returns `empty`. If channel is closed, | |
192 | returns `closed`. Otherwise it returns `success` and `va` contains the | |
193 | dequeued value[unblocking]]] | |
194 | [[Throws:] [Exceptions thrown by copy- or move-operations.]] | |
195 | ] | |
196 | ] | |
197 | [xchannel_try_pop unbounded_channel .] | |
198 | ||
199 | [template xchannel_pop_wait_until_effects[endtime unblocking] If channel | |
200 | is not empty, immediately dequeues a value from the channel. Otherwise | |
201 | the fiber gets suspended until at least one new item is `push()`ed (return | |
202 | value `success` and `va` contains dequeued value), or the channel gets | |
203 | `close()`d (return value `closed`), or the system time reaches [endtime] | |
204 | (return value `timeout`)[unblocking]] | |
205 | ||
206 | [template xchannel_pop_wait_for[cls unblocking] | |
207 | [member_heading [cls]..pop_wait_for] | |
208 | ||
209 | template< typename Rep, typename Period > | |
210 | channel_op_status pop_wait_for( | |
211 | value_type & va, | |
212 | std::chrono::duration< Rep, Period > const& timeout_duration) | |
213 | ||
214 | [variablelist | |
215 | [[Effects:] [Accepts `std::chrono::duration` and internally computes a timeout | |
216 | time as (system time + `timeout_duration`). | |
217 | [xchannel_pop_wait_until_effects the computed timeout time..[unblocking]]]] | |
218 | [[Throws:] [timeout-related exceptions.]] | |
219 | ] | |
220 | ] | |
221 | [xchannel_pop_wait_for unbounded_channel .] | |
222 | ||
223 | [template xchannel_pop_wait_until[cls unblocking] | |
224 | [member_heading [cls]..pop_wait_until] | |
225 | ||
226 | template< typename Clock, typename Duration > | |
227 | channel_op_status pop_wait_until( | |
228 | value_type & va, | |
229 | std::chrono::time_point< Clock, Duration > const& timeout_time) | |
230 | ||
231 | [variablelist | |
232 | [[Effects:] [Accepts a `std::chrono::time_point< Clock, Duration >`. | |
233 | [xchannel_pop_wait_until_effects the passed `time_point`..[unblocking]]]] | |
234 | [[Throws:] [timeout-related exceptions.]] | |
235 | ] | |
236 | ] | |
237 | [xchannel_pop_wait_until unbounded_channel .] | |
238 | ||
239 | ||
240 | [template_heading bounded_channel] | |
241 | ||
242 | #include <boost/fiber/bounded_channel.hpp> | |
243 | ||
244 | namespace boost { | |
245 | namespace fibers { | |
246 | ||
247 | template< typename T, typename __Allocator__ = __allocator__ > | |
248 | class bounded_channel { | |
249 | public: | |
250 | typedef T value_type; | |
251 | ||
252 | bounded_channel( std::size_t wm, __Allocator__ const& alloc = Allocator() ); | |
253 | bounded_channel( std::size_t hwm, std::size_t lwm, __Allocator__ const& alloc = Allocator() ); | |
254 | ||
255 | bounded_channel( bounded_channel const& other) = delete; | |
256 | bounded_channel & operator=( bounded_channel const& other) = delete; | |
257 | ||
258 | std::size_t upper_bound() const noexcept; | |
259 | std::size_t lower_bound() const noexcept; | |
260 | ||
261 | void close() noexcept; | |
262 | ||
263 | channel_op_status push( value_type const& va); | |
264 | channel_op_status push( value_type && va); | |
265 | template< typename Rep, typename Period > | |
266 | channel_op_status push_wait_for( | |
267 | value_type const& va, | |
268 | std::chrono::duration< Rep, Period > const& timeout_duration); | |
269 | channel_op_status push_wait_for( value_type && va, | |
270 | std::chrono::duration< Rep, Period > const& timeout_duration); | |
271 | template< typename Clock, typename Duration > | |
272 | channel_op_status push_wait_until( | |
273 | value_type const& va, | |
274 | std::chrono::time_point< Clock, Duration > const& timeout_time); | |
275 | template< typename Clock, typename Duration > | |
276 | channel_op_status push_wait_until( | |
277 | value_type && va, | |
278 | std::chrono::time_point< Clock, Duration > const& timeout_time); | |
279 | channel_op_status try_push( value_type const& va); | |
280 | channel_op_status try_push( value_type && va); | |
281 | ||
282 | channel_op_status pop( value_type & va); | |
283 | value_type value_pop(); | |
284 | template< typename Rep, typename Period > | |
285 | channel_op_status pop_wait_for( | |
286 | value_type & va, | |
287 | std::chrono::duration< Rep, Period > const& timeout_duration); | |
288 | template< typename Clock, typename Duration > | |
289 | channel_op_status pop_wait_until( | |
290 | value_type & va, | |
291 | std::chrono::time_point< Clock, Duration > const& timeout_time); | |
292 | channel_op_status try_pop( value_type & va); | |
293 | }; | |
294 | ||
295 | }} | |
296 | ||
297 | [heading Constructor] | |
298 | ||
299 | bounded_channel( std::size_t wm, __Allocator__ const& alloc = Allocator() ); | |
300 | bounded_channel( std::size_t hwm, std::size_t lwm, __Allocator__ const& alloc = Allocator() ); | |
301 | ||
302 | [variablelist | |
303 | [[Preconditions:] [`hwm > lwm`]] | |
304 | [[Effects:] [Constructs an object of class `bounded_channel`. The constructor | |
305 | with two arguments constructs an object of class `bounded_channel` with a | |
306 | high-watermark of `hwm` and a low-watermark of `lwm` items. The constructor | |
307 | with one `std::size_t` argument is effectively the same as `bounded_channel(wm, (wm-1), alloc)`. | |
308 | Internal nodes are allocated using `alloc` - C++11-allocators are supported.]] | |
309 | [[Throws:] [`fiber_error`]] | |
310 | [[Error Conditions:] [ | |
311 | [*invalid_argument]: if `lwm >= hwm`.]] | |
312 | [[Notes:] [Once the number of values in the channel reaches `hwm`, any call to | |
313 | `push()`, `push_wait_for()` or `push_wait_until()` will block until the number | |
314 | of values in the channel is at most `lwm`. That is, if `lwm < (hwm-1)`, the | |
315 | channel can be in a state in which `push()`, `push_wait_for()` or `push_wait_until()` | |
316 | calls will block (channel is full) even though the number of values | |
317 | in the channel is less than `hwm`.]] | |
318 | [[See also:] [__Allocator__ concept, __allocator__]] | |
319 | ] | |
320 | ||
321 | [member_heading bounded_channel..upper_bound] | |
322 | ||
323 | std::size_t upper_bound() const noexcept; | |
324 | ||
325 | [variablelist | |
326 | [[Returns:] [the high-watermark with which `*this` was constructed.]] | |
327 | [[Throws:] [Nothing.]] | |
328 | ] | |
329 | ||
330 | [member_heading bounded_channel..lower_bound] | |
331 | ||
332 | std::size_t lower_bound() const noexcept; | |
333 | ||
334 | [variablelist | |
335 | [[Returns:] [the low-watermark with which `*this` was constructed.]] | |
336 | [[Throws:] [Nothing.]] | |
337 | ] | |
338 | ||
339 | [xchannel_close bounded_channel] | |
340 | ||
341 | [template bounded_channel_push_effects[or] [xchannel_push_effects If channel | |
342 | is not full, enqueues] Otherwise the calling fiber is suspended until | |
343 | the number of values in the channel drops to `lwm` (return value | |
344 | `success`)[or] the channel is `close()`d (return value `closed`)] | |
345 | ||
346 | [member_heading bounded_channel..push] | |
347 | ||
348 | channel_op_status push( value_type const& va); | |
349 | channel_op_status push( value_type && va); | |
350 | ||
351 | [variablelist | |
352 | [[Effects:] [[bounded_channel_push_effects or].]] | |
353 | [[Throws:] [exceptions thrown by memory | |
354 | allocation and copying or moving `va`.]] | |
355 | ] | |
356 | ||
357 | [member_heading bounded_channel..push_wait_for] | |
358 | ||
359 | template< typename Rep, typename Period > | |
360 | channel_op_status push_wait_for( | |
361 | value_type const& va, | |
362 | std::chrono::duration< Rep, Period > const& timeout_duration); | |
363 | ||
364 | template< typename Rep, typename Period > | |
365 | channel_op_status push_wait_for( | |
366 | value_type && va, | |
367 | std::chrono::duration< Rep, Period > const& timeout_duration); | |
368 | ||
369 | [variablelist | |
370 | [[Effects:] [Accepts `std::chrono::duration` and internally computes a | |
371 | time_point as (system time + `timeout_duration`). | |
372 | [bounded_channel_push_effects ,], or the system time reaches the computed | |
373 | time_point (return value `timeout`).]] | |
374 | [[Throws:] [exceptions thrown by memory | |
375 | allocation and copying or moving `va` or timeout-related exceptions.]] | |
376 | ] | |
377 | ||
378 | [member_heading bounded_channel..push_wait_until] | |
379 | ||
380 | template< typename Clock, typename Duration > | |
381 | channel_op_status push_wait_until( | |
382 | value_type const& va, | |
383 | std::chrono::time_point< Clock, Duration > const& timeout_time); | |
384 | ||
385 | template< typename Clock, typename Duration > | |
386 | channel_op_status push_wait_until( | |
387 | value_type && va, | |
388 | std::chrono::time_point< Clock, Duration > const& timeout_time); | |
389 | ||
390 | [variablelist | |
391 | [[Effects:] [Accepts an absolute `timeout_time` in any supported time_point | |
392 | type. [bounded_channel_push_effects ,], or the system time reaches the passed | |
393 | time_point (return value `timeout`).]] | |
394 | [[Throws:] [exceptions thrown by memory | |
395 | allocation and copying or moving `va` or timeout-related exceptions.]] | |
396 | ] | |
397 | ||
398 | [member_heading bounded_channel..try_push] | |
399 | ||
400 | channel_op_status try_push( value_type const& va); | |
401 | channel_op_status try_push( value_type && va); | |
402 | ||
403 | [variablelist | |
404 | [[Effects:] [If channel is full, returns `full`. | |
405 | [xchannel_push_effects Otherwise enqueues]]] | |
406 | [[Throws:] [Exceptions thrown by memory | |
407 | allocation and copying or moving `va`.]] | |
408 | ] | |
409 | ||
410 | [template bounded_pop_unblocking[] Once the number of items remaining in the | |
411 | channel drops to `lwm`, any fibers blocked on `push()`, `push_wait_for()` | |
412 | or `push_wait_until()` may resume.] | |
413 | ||
414 | [xchannel_pop bounded_channel... [bounded_pop_unblocking]] | |
415 | [xchannel_value_pop bounded_channel... [bounded_pop_unblocking]] | |
416 | [xchannel_try_pop bounded_channel... [bounded_pop_unblocking]] | |
417 | [xchannel_pop_wait_for bounded_channel... [bounded_pop_unblocking]] | |
418 | [xchannel_pop_wait_until bounded_channel... [bounded_pop_unblocking]] | |
419 | ||
420 | [endsect] |