Refactors lock test cases backoff values
[libcds.git] / cds / misc / barrier.h
1 #ifndef _BARRIER_H
2 #define _BARRIER_H
3
4 #include "backoff.h"
5 #include <atomic>
6
7 namespace cds_others {
8
9 class SpinBarrier {
10 public:
11   SpinBarrier(unsigned int n) : n_(n) {
12     nwait_ = 0;
13     step_ = 0;
14   }
15
16   // The purpose of wait() is that threads that enter it synchronize with
17   // threads when they get out of it.
18   /** wildcard(2) is acq_rel, ensuring that all threads hb before other
19    *  threads in the rmw chain order, then the wildcard (4) and (5) are
20    *  release/acquire to make sure the last thread synchronize with all other
21    *  earlier threads. Plus, the (4) and (5) synchronization can make sure the
22    *  reset of nwait_ in wildcard(3) happens-before any other threads in the
23    *  later usage of the barrier.
24   */
25
26   bool wait() {
27     unsigned int step = step_.load(std::memory_order_relaxed);
28
29     if (nwait_.fetch_add(1, std::memory_order_acq_rel) == n_ - 1) {
30       /* OK, last thread to come.  */
31       nwait_.store(0, std::memory_order_relaxed);
32       step_.fetch_add(1, std::memory_order_release);
33       return true;
34     } else {
35       ExpBackoff backoff;
36       /* Run in circles and scream like a little girl.  */
37       while (step_.load(std::memory_order_acquire) == step) {
38         backoff();
39       }
40       return false;
41     }
42   }
43
44 protected:
45   /* Number of synchronized threads. */
46   const unsigned int n_;
47
48   /* Number of threads currently spinning.  */
49   std::atomic<unsigned int> nwait_;
50
51   /* Number of barrier syncronizations completed so far,
52    *      * it's OK to wrap.  */
53   std::atomic<unsigned int> step_;
54 };
55
56 } // namespace cds_others
57
58 #endif