boost asio allocation

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() << "\n";
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>\n";
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() << "\n";
212   }
213 
214   return 0;
215 }

 

posted @ 2017-11-16 15:27  karllen  阅读(925)  评论(0编辑  收藏  举报