SerialExecutor.h 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*
  2. * Copyright 2017-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. #include <atomic>
  18. #include <memory>
  19. #include <mutex>
  20. #include <folly/concurrency/UnboundedQueue.h>
  21. #include <folly/executors/GlobalExecutor.h>
  22. #include <folly/executors/SequencedExecutor.h>
  23. namespace folly {
  24. /**
  25. * @class SerialExecutor
  26. *
  27. * @brief Executor that guarantees serial non-concurrent execution of added
  28. * tasks
  29. *
  30. * SerialExecutor is similar to boost asio's strand concept. A SerialExecutor
  31. * has a parent executor which is given at construction time (defaults to
  32. * folly's global CPUExecutor). Tasks added to SerialExecutor are executed
  33. * in the parent executor, however strictly non-concurrently and in the order
  34. * they were added.
  35. *
  36. * SerialExecutor tries to schedule its tasks fairly. Every task submitted to
  37. * it results in one task submitted to the parent executor. Whenever the parent
  38. * executor executes one of those, one of the tasks submitted to SerialExecutor
  39. * is marked for execution, which means it will either be executed at once,
  40. * or if a task is currently being executed already, after that.
  41. *
  42. * The SerialExecutor may be deleted at any time. All tasks that have been
  43. * submitted will still be executed with the same guarantees, as long as the
  44. * parent executor is executing tasks.
  45. */
  46. class SerialExecutor : public SequencedExecutor {
  47. public:
  48. SerialExecutor(SerialExecutor const&) = delete;
  49. SerialExecutor& operator=(SerialExecutor const&) = delete;
  50. SerialExecutor(SerialExecutor&&) = delete;
  51. SerialExecutor& operator=(SerialExecutor&&) = delete;
  52. static KeepAlive<SerialExecutor> create(
  53. KeepAlive<Executor> parent = getKeepAliveToken(getCPUExecutor().get()));
  54. class Deleter {
  55. public:
  56. Deleter() {}
  57. void operator()(SerialExecutor* executor) {
  58. executor->keepAliveRelease();
  59. }
  60. private:
  61. friend class SerialExecutor;
  62. explicit Deleter(std::shared_ptr<Executor> parent)
  63. : parent_(std::move(parent)) {}
  64. std::shared_ptr<Executor> parent_;
  65. };
  66. using UniquePtr = std::unique_ptr<SerialExecutor, Deleter>;
  67. [[deprecated("Replaced by create")]] static UniquePtr createUnique(
  68. std::shared_ptr<Executor> parent = getCPUExecutor());
  69. /**
  70. * Add one task for execution in the parent executor
  71. */
  72. void add(Func func) override;
  73. /**
  74. * Add one task for execution in the parent executor, and use the given
  75. * priority for one task submission to parent executor.
  76. *
  77. * Since in-order execution of tasks submitted to SerialExecutor is
  78. * guaranteed, the priority given here does not necessarily reflect the
  79. * execution priority of the task submitted with this call to
  80. * `addWithPriority`. The given priority is passed on to the parent executor
  81. * for the execution of one of the SerialExecutor's tasks.
  82. */
  83. void addWithPriority(Func func, int8_t priority) override;
  84. uint8_t getNumPriorities() const override {
  85. return parent_->getNumPriorities();
  86. }
  87. protected:
  88. bool keepAliveAcquire() override;
  89. void keepAliveRelease() override;
  90. private:
  91. explicit SerialExecutor(KeepAlive<Executor> parent);
  92. ~SerialExecutor() override;
  93. void run();
  94. KeepAlive<Executor> parent_;
  95. std::atomic<std::size_t> scheduled_{0};
  96. /**
  97. * Unbounded multi producer single consumer queue where consumers don't block
  98. * on dequeue.
  99. */
  100. folly::UnboundedQueue<Func, false, true, false> queue_;
  101. std::atomic<ssize_t> keepAliveCounter_{1};
  102. };
  103. } // namespace folly