condition_variable.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. // ConditionVariable wraps pthreads condition variable synchronization or, on
  5. // Windows, simulates it. This functionality is very helpful for having
  6. // several threads wait for an event, as is common with a thread pool managed
  7. // by a master. The meaning of such an event in the (worker) thread pool
  8. // scenario is that additional tasks are now available for processing. It is
  9. // used in Chrome in the DNS prefetching system to notify worker threads that
  10. // a queue now has items (tasks) which need to be tended to. A related use
  11. // would have a pool manager waiting on a ConditionVariable, waiting for a
  12. // thread in the pool to announce (signal) that there is now more room in a
  13. // (bounded size) communications queue for the manager to deposit tasks, or,
  14. // as a second example, that the queue of tasks is completely empty and all
  15. // workers are waiting.
  16. //
  17. // USAGE NOTE 1: spurious signal events are possible with this and
  18. // most implementations of condition variables. As a result, be
  19. // *sure* to retest your condition before proceeding. The following
  20. // is a good example of doing this correctly:
  21. //
  22. // while (!work_to_be_done()) Wait(...);
  23. //
  24. // In contrast do NOT do the following:
  25. //
  26. // if (!work_to_be_done()) Wait(...); // Don't do this.
  27. //
  28. // Especially avoid the above if you are relying on some other thread only
  29. // issuing a signal up *if* there is work-to-do. There can/will
  30. // be spurious signals. Recheck state on waiting thread before
  31. // assuming the signal was intentional. Caveat caller ;-).
  32. //
  33. // USAGE NOTE 2: Broadcast() frees up all waiting threads at once,
  34. // which leads to contention for the locks they all held when they
  35. // called Wait(). This results in POOR performance. A much better
  36. // approach to getting a lot of threads out of Wait() is to have each
  37. // thread (upon exiting Wait()) call Signal() to free up another
  38. // Wait'ing thread. Look at condition_variable_unittest.cc for
  39. // both examples.
  40. //
  41. // Broadcast() can be used nicely during teardown, as it gets the job
  42. // done, and leaves no sleeping threads... and performance is less
  43. // critical at that point.
  44. //
  45. // The semantics of Broadcast() are carefully crafted so that *all*
  46. // threads that were waiting when the request was made will indeed
  47. // get signaled. Some implementations mess up, and don't signal them
  48. // all, while others allow the wait to be effectively turned off (for
  49. // a while while waiting threads come around). This implementation
  50. // appears correct, as it will not "lose" any signals, and will guarantee
  51. // that all threads get signaled by Broadcast().
  52. //
  53. // This implementation offers support for "performance" in its selection of
  54. // which thread to revive. Performance, in direct contrast with "fairness,"
  55. // assures that the thread that most recently began to Wait() is selected by
  56. // Signal to revive. Fairness would (if publicly supported) assure that the
  57. // thread that has Wait()ed the longest is selected. The default policy
  58. // may improve performance, as the selected thread may have a greater chance of
  59. // having some of its stack data in various CPU caches.
  60. #ifndef BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
  61. #define BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
  62. #include "base/dcheck_is_on.h"
  63. #include "base/memory/raw_ptr.h"
  64. #include "build/build_config.h"
  65. #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
  66. #include <pthread.h>
  67. #endif
  68. #include "base/base_export.h"
  69. #include "base/synchronization/lock.h"
  70. #if BUILDFLAG(IS_WIN)
  71. #include "base/win/windows_types.h"
  72. #endif
  73. namespace base {
  74. class TimeDelta;
  75. class BASE_EXPORT ConditionVariable {
  76. public:
  77. // Construct a cv for use with ONLY one user lock.
  78. explicit ConditionVariable(Lock* user_lock);
  79. ConditionVariable(const ConditionVariable&) = delete;
  80. ConditionVariable& operator=(const ConditionVariable&) = delete;
  81. ~ConditionVariable();
  82. // Wait() releases the caller's critical section atomically as it starts to
  83. // sleep, and the reacquires it when it is signaled. The wait functions are
  84. // susceptible to spurious wakeups. (See usage note 1 for more details.)
  85. void NOT_TAIL_CALLED Wait();
  86. void NOT_TAIL_CALLED TimedWait(const TimeDelta& max_time);
  87. // Broadcast() revives all waiting threads. (See usage note 2 for more
  88. // details.)
  89. void Broadcast();
  90. // Signal() revives one waiting thread.
  91. void Signal();
  92. // Declares that this ConditionVariable will only ever be used by a thread
  93. // that is idle at the bottom of its stack and waiting for work (in
  94. // particular, it is not synchronously waiting on this ConditionVariable
  95. // before resuming ongoing work). This is useful to avoid telling
  96. // base-internals that this thread is "blocked" when it's merely idle and
  97. // ready to do work. As such, this is only expected to be used by thread and
  98. // thread pool impls.
  99. void declare_only_used_while_idle() { waiting_is_blocking_ = false; }
  100. private:
  101. #if BUILDFLAG(IS_WIN)
  102. CHROME_CONDITION_VARIABLE cv_;
  103. const raw_ptr<CHROME_SRWLOCK> srwlock_;
  104. #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
  105. pthread_cond_t condition_;
  106. raw_ptr<pthread_mutex_t> user_mutex_;
  107. #endif
  108. #if DCHECK_IS_ON()
  109. const raw_ptr<base::Lock>
  110. user_lock_; // Needed to adjust shadow lock state on wait.
  111. #endif
  112. // Whether a thread invoking Wait() on this ConditionalVariable should be
  113. // considered blocked as opposed to idle (and potentially replaced if part of
  114. // a pool).
  115. bool waiting_is_blocking_ = true;
  116. };
  117. } // namespace base
  118. #endif // BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_