]>
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:asio Example: asynchronous network I/O (boost.asio)] | |
9 | ||
10 | In the past, code using asio's ['asynchronous operations] was scattered by | |
11 | callbacks. | |
12 | __boost_asio__ provides with its new ['asynchronous result] feature a new way to | |
13 | simplify the code and make it easier to read. | |
14 | __yield_context__ internally uses __boost_coroutine__: | |
15 | ||
16 | void echo(boost::asio::ip::tcp::socket& socket,boost::asio::yield_context yield){ | |
17 | char data[128]; | |
18 | // read asynchronous data from socket | |
19 | // execution context will be suspended until | |
20 | // some bytes are read from socket | |
21 | std::size_t n=socket.async_read_some(boost::asio::buffer(data),yield); | |
22 | // write some bytes asynchronously | |
23 | boost::asio::async_write(socket,boost::asio::buffer(data,n),yield); | |
24 | } | |
25 | ||
26 | Unfortunately __boost_coroutine__ (__yield_context__) does not provide | |
27 | primitives to synchronize different coroutines (execution contexts). | |
28 | ||
29 | __boost_fiber__ provides an example how __fibers__ could be integrated into | |
30 | __boost_asio__ so that ['asynchronous operations] from __boost_asio__ can be | |
31 | used together with fibers, synchronized by primitives provided by | |
32 | __boost_fiber__. | |
33 | ||
34 | The example section contains a complete publish-subscribe application | |
35 | demonstrating the use of fibers with asio's ['asynchronous operations]. | |
36 | __yield_fiber__ abstracts the fiber in asio's context. | |
37 | ||
38 | void subscriber::run( boost::fibers::asio::yield_fiber yield) | |
39 | { | |
40 | boost::system::error_code ec; | |
41 | ||
42 | // read first message == channel name | |
43 | std::string channel; | |
44 | boost::asio::async_read( | |
45 | socket_, | |
46 | boost::asio::buffer( channel), | |
47 | yield[ec]); | |
48 | if ( ec) throw std::runtime_error("no channel from subscriber"); | |
49 | ||
50 | // register new channel | |
51 | reg_.subscribe( channel, shared_from_this() ); | |
52 | ||
53 | for (;;) | |
54 | { | |
55 | boost::fibers::mutex::scoped_lock lk( mtx_); | |
56 | // wait for published messages | |
57 | // fiber gets suspended and will be woken up if a | |
58 | // new message has to be published to subscriber | |
59 | cond_.wait( lk); | |
60 | ||
61 | // '<fini>' terminates subscriber | |
62 | // data_ is a private member of subscriber and | |
63 | // gets filled by the publisher | |
64 | // notification of available data via condition_var cond_ | |
65 | if ( "<fini>" == std::string( data_) ) break; | |
66 | ||
67 | // write message asynchronously to subscriber | |
68 | // fiber gets suspended until message was written | |
69 | boost::asio::async_write( | |
70 | socket_, | |
71 | boost::asio::buffer( data_, max_length), | |
72 | yield[ec]); | |
73 | if ( ec) throw std::runtime_error("publishing message failed"); | |
74 | } | |
75 | } | |
76 | ||
77 | [heading C10K problem] | |
78 | ||
79 | The C10K-website [footnote [@http://www.kegel.com/c10k.html 'The C10K problem', | |
80 | Dan Kegel]] | |
81 | from Dan Kegel describes the problem of handling ten thousand clients | |
82 | simultaneously and which strategies are possible. | |
83 | ||
84 | __boost_fiber__ and __boost_asio__ support the strategy 'serve many clients with | |
85 | each server thread, and use asynchronous I/O' without scattering the logic | |
86 | across many callbacks (as was asio's previous strategy) and overloading the | |
87 | operating system with too many threads. (Beyond a certain number of threads, the | |
88 | overhead of the kernel scheduler starts to swamp the available cores.) | |
89 | ||
90 | Because __boost_fiber__ contains synchronization primitives, it is easy to | |
91 | synchronize different fibers and use asynchronous network I/O at the same | |
92 | time. | |
93 | ||
94 | __boost_fiber__ provides the same classes and interfaces as __boost_thread__. | |
95 | Therefore developers are able to use patterns familiar from multi-threaded | |
96 | programming. For instance the strategy 'serve one client with one thread' | |
97 | could be transformed into 'serve one client with one fiber'. | |
98 | ||
99 | [heading Integration] | |
100 | ||
101 | The code for integrating boost.fiber int boost.asio can be found in the example | |
102 | directory. The author believes, that a better, more tight integration is | |
103 | possible but requires input of boost.asio's author and maybe some changes in the | |
104 | boost.asio framework. | |
105 | ||
106 | The current integration pattern requires to runn __io_service__ in | |
107 | __run_service__ (separate fiber). | |
108 | ||
109 | ||
110 | [endsect] |