allocation演示了自定义异步操作的内存分配策略,因为asio在执行异步IO操作时会使用系统函数来动态分配内存,使用完后便立即释放掉;在IO操作密集的应用中,这种内存动态分配策略会较大地影响程序的整体性能。为了避免这个问题,可以在在应用程序中创建一个内存块供asio异步IO操作使用,异步IO操作通过自定义接口 asio_handler_allocate 和 asio_handler_deallocate 来使用该内存块。该例子中使用到了 boost::aligned_storage<1024> storage_ 来管理原始内存。
cpp03
1 // 2 // server.cpp 3 // ~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 // 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) 9 // 10 11 #include <cstdlib> 12 #include <iostream> 13 #include <boost/aligned_storage.hpp> 14 #include <boost/array.hpp> 15 #include <boost/bind.hpp> 16 #include <boost/enable_shared_from_this.hpp> 17 #include <boost/noncopyable.hpp> 18 #include <boost/shared_ptr.hpp> 19 #include <boost/asio.hpp> 20 21 22 using boost::asio::ip::tcp; 23 24 // Class to manage the memory to be used for handler-based custom allocation. 25 // It contains a single block of memory which may be returned for allocation 26 // requests. If the memory is in use when an allocation request is made, the 27 // allocator delegates allocation to the global heap. 28 class handler_allocator 29 : private boost::noncopyable 30 { 31 public: 32 handler_allocator() 33 : in_use_(false) 34 { 35 } 36 37 void* allocate(std::size_t size) 38 { 39 if (!in_use_ && size < storage_.size) 40 { 41 in_use_ = true; 42 return storage_.address(); 43 } 44 else 45 { 46 return ::operator new(size); 47 } 48 } 49 50 void deallocate(void* pointer) 51 { 52 if (pointer == storage_.address()) 53 { 54 in_use_ = false; 55 } 56 else 57 { 58 ::operator delete(pointer); 59 } 60 } 61 62 private: 63 // Storage space used for handler-based custom memory allocation. 64 boost::aligned_storage<1024> storage_; 65 66 // Whether the handler-based custom allocation storage has been used. 67 bool in_use_; 68 }; 69 70 // Wrapper class template for handler objects to allow handler memory 71 // allocation to be customised. Calls to operator() are forwarded to the 72 // encapsulated handler. 73 template <typename Handler> 74 class custom_alloc_handler 75 { 76 public: 77 custom_alloc_handler(handler_allocator& a, Handler h) 78 : allocator_(a), 79 handler_(h) 80 { 81 } 82 83 template <typename Arg1> 84 void operator()(Arg1 arg1) 85 { 86 handler_(arg1); 87 } 88 89 template <typename Arg1, typename Arg2> 90 void operator()(Arg1 arg1, Arg2 arg2) 91 { 92 handler_(arg1, arg2); 93 } 94 95 friend void* asio_handler_allocate(std::size_t size, 96 custom_alloc_handler<Handler>* this_handler) 97 { 98 return this_handler->allocator_.allocate(size); 99 } 100 101 friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/, 102 custom_alloc_handler<Handler>* this_handler) 103 { 104 this_handler->allocator_.deallocate(pointer); 105 } 106 private: 107 handler_allocator& allocator_; 108 Handler handler_; 109 }; 110 // Helper function to wrap a handler object to add custom allocation. 111 template <typename Handler> 112 inline custom_alloc_handler<Handler> make_custom_alloc_handler( 113 handler_allocator& a, Handler h) 114 { 115 return custom_alloc_handler<Handler>(a, h); 116 } 117 118 class session 119 : public boost::enable_shared_from_this<session> 120 { 121 public: 122 session(boost::asio::io_service& io_service) 123 : socket_(io_service) 124 { 125 } 126 tcp::socket& socket() 127 { 128 return socket_; 129 } 130 void start() 131 { 132 socket_.async_read_some(boost::asio::buffer(data_), 133 make_custom_alloc_handler(allocator_, 134 boost::bind(&session::handle_read, 135 shared_from_this(), 136 boost::asio::placeholders::error, 137 boost::asio::placeholders::bytes_transferred))); 138 } 139 void handle_read(const boost::system::error_code& error, 140 size_t bytes_transferred) 141 { 142 if (!error) 143 { 144 boost::asio::async_write(socket_, 145 boost::asio::buffer(data_, bytes_transferred), 146 make_custom_alloc_handler(allocator_, 147 boost::bind(&session::handle_write, 148 shared_from_this(), 149 boost::asio::placeholders::error))); 150 } 151 } 152 void handle_write(const boost::system::error_code& error) 153 { 154 if (!error) 155 { 156 socket_.async_read_some(boost::asio::buffer(data_), 157 make_custom_alloc_handler(allocator_, 158 boost::bind(&session::handle_read, 159 shared_from_this(), 160 boost::asio::placeholders::error, 161 boost::asio::placeholders::bytes_transferred))); 162 } 163 } 164 private: 165 // The socket used to communicate with the client. 166 tcp::socket socket_; 167 // Buffer used to store data received from the client. 168 boost::array<char, 1024> data_; 169 // The allocator to use for handler-based custom memory allocation. 170 handler_allocator allocator_; 171 }; 172 173 typedef boost::shared_ptr<session> session_ptr; 174 class server 175 { 176 public: 177 server(boost::asio::io_service& io_service, short port) 178 : io_service_(io_service), 179 acceptor_(io_service, tcp::endpoint(tcp::v4(), port)) 180 { 181 session_ptr new_session(new session(io_service_)); 182 acceptor_.async_accept(new_session->socket(), 183 boost::bind(&server::handle_accept, this, new_session, 184 boost::asio::placeholders::error)); 185 } 186 void handle_accept(session_ptr new_session, 187 const boost::system::error_code& error) 188 { 189 if (!error) 190 { 191 new_session->start(); 192 } 193 194 new_session.reset(new session(io_service_)); 195 acceptor_.async_accept(new_session->socket(), 196 boost::bind(&server::handle_accept, this, new_session, 197 boost::asio::placeholders::error)); 198 } 199 private: 200 boost::asio::io_service& io_service_; 201 tcp::acceptor acceptor_; 202 }; 203 204 int main(int argc, char* argv[]) 205 { 206 try 207 { 208 boost::asio::io_service io_service; 209 using namespace std; // For atoi. 210 server s(io_service, 4004); 211 io_service.run(); 212 } 213 catch (std::exception& e) 214 { 215 std::cerr << "Exception: " << e.what() << " "; 216 } 217 218 return 0; 219 }
cpp11
1 // 2 // server.cpp 3 // ~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 // 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) 9 // 10 11 #include <array> 12 #include <cstdlib> 13 #include <iostream> 14 #include <memory> 15 #include <type_traits> 16 #include <utility> 17 #include "asio.hpp" 18 19 using asio::ip::tcp; 20 21 // Class to manage the memory to be used for handler-based custom allocation. 22 // It contains a single block of memory which may be returned for allocation 23 // requests. If the memory is in use when an allocation request is made, the 24 // allocator delegates allocation to the global heap. 25 class handler_allocator 26 { 27 public: 28 handler_allocator() 29 : in_use_(false) 30 { 31 } 32 33 handler_allocator(const handler_allocator&) = delete; 34 handler_allocator& operator=(const handler_allocator&) = delete; 35 36 void* allocate(std::size_t size) 37 { 38 if (!in_use_ && size < sizeof(storage_)) 39 { 40 in_use_ = true; 41 return &storage_; 42 } 43 else 44 { 45 return ::operator new(size); 46 } 47 } 48 49 void deallocate(void* pointer) 50 { 51 if (pointer == &storage_) 52 { 53 in_use_ = false; 54 } 55 else 56 { 57 ::operator delete(pointer); 58 } 59 } 60 61 private: 62 // Storage space used for handler-based custom memory allocation. 63 typename std::aligned_storage<1024>::type storage_; 64 65 // Whether the handler-based custom allocation storage has been used. 66 bool in_use_; 67 }; 68 69 // Wrapper class template for handler objects to allow handler memory 70 // allocation to be customised. Calls to operator() are forwarded to the 71 // encapsulated handler. 72 template <typename Handler> 73 class custom_alloc_handler 74 { 75 public: 76 custom_alloc_handler(handler_allocator& a, Handler h) 77 : allocator_(a), 78 handler_(h) 79 { 80 } 81 82 template <typename ...Args> 83 void operator()(Args&&... args) 84 { 85 handler_(std::forward<Args>(args)...); 86 } 87 88 friend void* asio_handler_allocate(std::size_t size, 89 custom_alloc_handler<Handler>* this_handler) 90 { 91 return this_handler->allocator_.allocate(size); 92 } 93 94 friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/, 95 custom_alloc_handler<Handler>* this_handler) 96 { 97 this_handler->allocator_.deallocate(pointer); 98 } 99 100 private: 101 handler_allocator& allocator_; 102 Handler handler_; 103 }; 104 105 // Helper function to wrap a handler object to add custom allocation. 106 template <typename Handler> 107 inline custom_alloc_handler<Handler> make_custom_alloc_handler( 108 handler_allocator& a, Handler h) 109 { 110 return custom_alloc_handler<Handler>(a, h); 111 } 112 113 class session 114 : public std::enable_shared_from_this<session> 115 { 116 public: 117 session(tcp::socket socket) 118 : socket_(std::move(socket)) 119 { 120 } 121 122 void start() 123 { 124 do_read(); 125 } 126 127 private: 128 void do_read() 129 { 130 auto self(shared_from_this()); 131 socket_.async_read_some(asio::buffer(data_), 132 make_custom_alloc_handler(allocator_, 133 [this, self](std::error_code ec, std::size_t length) 134 { 135 if (!ec) 136 { 137 do_write(length); 138 } 139 })); 140 } 141 142 void do_write(std::size_t length) 143 { 144 auto self(shared_from_this()); 145 asio::async_write(socket_, asio::buffer(data_, length), 146 make_custom_alloc_handler(allocator_, 147 [this, self](std::error_code ec, std::size_t /*length*/) 148 { 149 if (!ec) 150 { 151 do_read(); 152 } 153 })); 154 } 155 156 // The socket used to communicate with the client. 157 tcp::socket socket_; 158 159 // Buffer used to store data received from the client. 160 std::array<char, 1024> data_; 161 162 // The allocator to use for handler-based custom memory allocation. 163 handler_allocator allocator_; 164 }; 165 166 class server 167 { 168 public: 169 server(asio::io_service& io_service, short port) 170 : acceptor_(io_service, tcp::endpoint(tcp::v4(), port)), 171 socket_(io_service) 172 { 173 do_accept(); 174 } 175 176 private: 177 void do_accept() 178 { 179 acceptor_.async_accept(socket_, 180 [this](std::error_code ec) 181 { 182 if (!ec) 183 { 184 std::make_shared<session>(std::move(socket_))->start(); 185 } 186 187 do_accept(); 188 }); 189 } 190 191 tcp::acceptor acceptor_; 192 tcp::socket socket_; 193 }; 194 195 int main(int argc, char* argv[]) 196 { 197 try 198 { 199 if (argc != 2) 200 { 201 std::cerr << "Usage: server <port> "; 202 return 1; 203 } 204 205 asio::io_service io_service; 206 server s(io_service, std::atoi(argv[1])); 207 io_service.run(); 208 } 209 catch (std::exception& e) 210 { 211 std::cerr << "Exception: " << e.what() << " "; 212 } 213 214 return 0; 215 }