Barrier.h 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*
  2. * Copyright 2015-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 <cstdint>
  19. #include <folly/futures/Future.h>
  20. #include <folly/futures/Promise.h>
  21. namespace folly {
  22. namespace futures {
  23. // A folly::Future-istic Barrier synchronization primitive
  24. //
  25. // The barrier is initialized with a count N.
  26. //
  27. // The first N-1 calls to wait() return uncompleted futures.
  28. //
  29. // The Nth call to wait() completes the previous N-1 futures successfully,
  30. // returns a future that is already completed successfully, and resets the
  31. // barrier; the barrier may be reused immediately, as soon as at least one
  32. // of the future completions has been observed.
  33. //
  34. // Of these N futures, exactly one is completed with true, while the others are
  35. // completed with false; it is unspecified which future completes with true.
  36. // (This may be used to elect a "leader" among a group of threads.)
  37. //
  38. // If the barrier is destroyed, any futures already returned by wait() will
  39. // complete with an error.
  40. class Barrier {
  41. public:
  42. explicit Barrier(uint32_t n);
  43. ~Barrier();
  44. folly::Future<bool> wait();
  45. private:
  46. typedef folly::Promise<bool> BoolPromise;
  47. static constexpr uint64_t kReaderShift = 32;
  48. static constexpr uint64_t kReader = uint64_t(1) << kReaderShift;
  49. static constexpr uint64_t kValueMask = kReader - 1;
  50. // For each "epoch" that the barrier is active, we have a different
  51. // ControlBlock. The ControlBlock contains the current barrier value
  52. // and the number of readers (currently inside wait()) packed into a
  53. // 64-bit value.
  54. //
  55. // The ControlBlock is allocated as long as either:
  56. // - there are threads currently inside wait() (reader count > 0), or
  57. // - the value has not yet reached size_ (value < size_)
  58. //
  59. // The array of size_ Promise objects is allocated immediately following
  60. // valueAndReaderCount.
  61. struct ControlBlock {
  62. // Reader count in most significant 32 bits
  63. // Value in least significant 32 bits
  64. std::atomic<uint64_t> valueAndReaderCount{0};
  65. };
  66. struct ControlBlockAndPromise {
  67. ControlBlock cb;
  68. BoolPromise promises[1];
  69. };
  70. static BoolPromise* promises(ControlBlock* cb) {
  71. return reinterpret_cast<ControlBlockAndPromise*>(cb)->promises;
  72. }
  73. static size_t controlBlockSize(size_t n) {
  74. return offsetof(ControlBlockAndPromise, promises) + n * sizeof(BoolPromise);
  75. }
  76. ControlBlock* allocateControlBlock();
  77. void freeControlBlock(ControlBlock* b);
  78. uint32_t size_;
  79. std::atomic<ControlBlock*> controlBlock_;
  80. };
  81. } // namespace futures
  82. } // namespace folly