coro_signal_group.hpp 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #ifndef SOPHIAR2_CORO_SIGNAL_GROUP_HPP
  2. #define SOPHIAR2_CORO_SIGNAL_GROUP_HPP
  3. #include "utility/coro_signal2.hpp"
  4. #include "utility/coro_worker.hpp"
  5. #include <boost/dynamic_bitset.hpp>
  6. #include <memory>
  7. #include <type_traits>
  8. #include <utility>
  9. #include <vector>
  10. namespace sophiar {
  11. template<auto CondFunc>
  12. class coro_signal_group {
  13. public:
  14. using pointer = std::unique_ptr<coro_signal_group<CondFunc>>;
  15. coro_signal_group() = default;
  16. ~coro_signal_group() {
  17. assert(!is_running);
  18. }
  19. static pointer new_instance() {
  20. return std::make_unique<coro_signal_group<CondFunc>>();
  21. }
  22. void add_watcher(signal_watcher &&watcher) {
  23. assert(!is_running);
  24. watcher_list.push_back(std::move(watcher));
  25. }
  26. auto new_watcher() {
  27. return final_signal.new_watcher();
  28. }
  29. void start(bool auto_sync = true) { // 思考如果 auto_sync == false 有什么副作用?
  30. assert(!is_running);
  31. item_mask.resize(watcher_list.size());
  32. is_running = true;
  33. for (size_t index = 0; index < watcher_list.size(); ++index) {
  34. auto worker = make_infinite_coro_worker([this, index, auto_sync]()
  35. -> boost::asio::awaitable<bool> {
  36. co_await watcher_list[index].coro_wait(auto_sync);
  37. item_mask.set(index);
  38. check_and_notify();
  39. co_return true;
  40. });
  41. worker->run();
  42. worker_list.push_back(std::move(worker));
  43. }
  44. }
  45. boost::asio::awaitable<void> stop() {
  46. for (auto &worker: worker_list) {
  47. worker->cancel();
  48. }
  49. for (auto &worker: worker_list) {
  50. co_await worker->coro_wait_stop();
  51. }
  52. worker_list.clear();
  53. is_running = false;
  54. }
  55. private:
  56. using bitset_type = boost::dynamic_bitset<>;
  57. static_assert(std::is_convertible_v<decltype(CondFunc(std::declval<bitset_type &>())), bool>);
  58. bool is_running = false;
  59. coro_signal2 final_signal;
  60. bitset_type item_mask;
  61. std::vector<signal_watcher> watcher_list;
  62. std::vector<coro_worker::pointer> worker_list;
  63. void check_and_notify() {
  64. if (!CondFunc(item_mask)) return;
  65. item_mask.reset();
  66. final_signal.try_notify_all();
  67. }
  68. };
  69. using coro_signal_all_group = coro_signal_group<[](auto &mask) { return mask.all(); }>;
  70. using coro_signal_any_group = coro_signal_group<[](auto &mask) { return mask.any(); }>;
  71. }
  72. #endif //SOPHIAR2_CORO_SIGNAL_GROUP_HPP