prioritised_handlers.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. //
  2. // prioritised_handlers.cpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2019 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. #include <boost/asio.hpp>
  11. #include <boost/function.hpp>
  12. #include <iostream>
  13. #include <queue>
  14. using boost::asio::ip::tcp;
  15. class handler_priority_queue : public boost::asio::execution_context
  16. {
  17. public:
  18. void add(int priority, boost::function<void()> function)
  19. {
  20. handlers_.push(queued_handler(priority, function));
  21. }
  22. void execute_all()
  23. {
  24. while (!handlers_.empty())
  25. {
  26. queued_handler handler = handlers_.top();
  27. handler.execute();
  28. handlers_.pop();
  29. }
  30. }
  31. class executor
  32. {
  33. public:
  34. executor(handler_priority_queue& q, int p)
  35. : context_(q), priority_(p)
  36. {
  37. }
  38. handler_priority_queue& context() const
  39. {
  40. return context_;
  41. }
  42. template <typename Function, typename Allocator>
  43. void dispatch(const Function& f, const Allocator&) const
  44. {
  45. context_.add(priority_, f);
  46. }
  47. template <typename Function, typename Allocator>
  48. void post(const Function& f, const Allocator&) const
  49. {
  50. context_.add(priority_, f);
  51. }
  52. template <typename Function, typename Allocator>
  53. void defer(const Function& f, const Allocator&) const
  54. {
  55. context_.add(priority_, f);
  56. }
  57. void on_work_started() const {}
  58. void on_work_finished() const {}
  59. bool operator==(const executor& other) const
  60. {
  61. return &context_ == &other.context_ && priority_ == other.priority_;
  62. }
  63. bool operator!=(const executor& other) const
  64. {
  65. return !operator==(other);
  66. }
  67. private:
  68. handler_priority_queue& context_;
  69. int priority_;
  70. };
  71. template <typename Handler>
  72. boost::asio::executor_binder<Handler, executor>
  73. wrap(int priority, Handler handler)
  74. {
  75. return boost::asio::bind_executor(executor(*this, priority), handler);
  76. }
  77. private:
  78. class queued_handler
  79. {
  80. public:
  81. queued_handler(int p, boost::function<void()> f)
  82. : priority_(p), function_(f)
  83. {
  84. }
  85. void execute()
  86. {
  87. function_();
  88. }
  89. friend bool operator<(const queued_handler& a,
  90. const queued_handler& b)
  91. {
  92. return a.priority_ < b.priority_;
  93. }
  94. private:
  95. int priority_;
  96. boost::function<void()> function_;
  97. };
  98. std::priority_queue<queued_handler> handlers_;
  99. };
  100. //----------------------------------------------------------------------
  101. void high_priority_handler(const boost::system::error_code& /*ec*/)
  102. {
  103. std::cout << "High priority handler\n";
  104. }
  105. void middle_priority_handler(const boost::system::error_code& /*ec*/)
  106. {
  107. std::cout << "Middle priority handler\n";
  108. }
  109. void low_priority_handler()
  110. {
  111. std::cout << "Low priority handler\n";
  112. }
  113. int main()
  114. {
  115. boost::asio::io_context io_context;
  116. handler_priority_queue pri_queue;
  117. // Post a completion handler to be run immediately.
  118. boost::asio::post(io_context, pri_queue.wrap(0, low_priority_handler));
  119. // Start an asynchronous accept that will complete immediately.
  120. tcp::endpoint endpoint(boost::asio::ip::address_v4::loopback(), 0);
  121. tcp::acceptor acceptor(io_context, endpoint);
  122. tcp::socket server_socket(io_context);
  123. acceptor.async_accept(server_socket,
  124. pri_queue.wrap(100, high_priority_handler));
  125. tcp::socket client_socket(io_context);
  126. client_socket.connect(acceptor.local_endpoint());
  127. // Set a deadline timer to expire immediately.
  128. boost::asio::steady_timer timer(io_context);
  129. timer.expires_at(boost::asio::steady_timer::time_point::min());
  130. timer.async_wait(pri_queue.wrap(42, middle_priority_handler));
  131. while (io_context.run_one())
  132. {
  133. // The custom invocation hook adds the handlers to the priority queue
  134. // rather than executing them from within the poll_one() call.
  135. while (io_context.poll_one())
  136. ;
  137. pri_queue.execute_all();
  138. }
  139. return 0;
  140. }