summaryrefslogtreecommitdiff
path: root/ACE/ace/Barrier.h
blob: 562d4467f1182483ce50829b8bf74423c8051073 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
// -*- C++ -*-

//==========================================================================
/**
 *  @file    Barrier.h
 *
 *  $Id$
 *
 *   Moved from Synch.h.
 *
 *  @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
 */
//==========================================================================

#ifndef ACE_BARRIER_H
#define ACE_BARRIER_H
#include /**/ "ace/pre.h"

#include /**/ "ace/ACE_export.h"

#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */

#include /**/ "ace/config-all.h"

// ACE platform supports some form of threading.
#if !defined (ACE_HAS_THREADS)

#include "ace/OS_NS_errno.h"

ACE_BEGIN_VERSIONED_NAMESPACE_DECL

/**
 * @class ACE_Barrier
 *
 * @brief This is a no-op to make ACE "syntactically consistent."
 */
class ACE_Export ACE_Barrier
{
public:
  ACE_Barrier (unsigned int, const ACE_TCHAR * = 0, void * = 0) {}
  ~ACE_Barrier (void) {}
  int wait (void) { ACE_NOTSUP_RETURN (-1); }
  void dump (void) const {}
};

ACE_END_VERSIONED_NAMESPACE_DECL

#else /* ACE_HAS_THREADS */

#include "ace/Condition_Thread_Mutex.h"

ACE_BEGIN_VERSIONED_NAMESPACE_DECL

struct ACE_Export ACE_Sub_Barrier
{
  // = Initialization.
  ACE_Sub_Barrier (unsigned int count,
                   ACE_Thread_Mutex &lock,
                   const ACE_TCHAR *name = 0,
                   void *arg = 0);

  ~ACE_Sub_Barrier (void);

  /// True if this generation of the barrier is done.
  ACE_Condition_Thread_Mutex barrier_finished_;

  /// Number of threads that are still running.
  int running_threads_;

  /// Dump the state of an object.
  void dump (void) const;

  /// Declare the dynamic allocation hooks.
  ACE_ALLOC_HOOK_DECLARE;
};

/**
 * @class ACE_Barrier
 *
 * @brief Implements "barrier synchronization".
 *
 * This class allows <count> number of threads to synchronize
 * their completion of (one round of) a task, which is known as
 * "barrier synchronization".   After all the threads call <wait()>
 * on the barrier they are all atomically released and can begin a new
 * round.
 *
 * This implementation uses a "sub-barrier generation numbering"
 * scheme to avoid overhead and to ensure that all threads wait to
 * leave the barrier correct.  This code is based on an article from
 * SunOpsis Vol. 4, No. 1 by Richard Marejka
 * (Richard.Marejka@canada.sun.com).
 */
class ACE_Export ACE_Barrier
{
public:
  /// Initialize the barrier to synchronize @a count threads.
  ACE_Barrier (unsigned int count,
               const ACE_TCHAR *name = 0,
               void *arg = 0);

  /// Default destructor.
  ~ACE_Barrier (void);

  /// Block the caller until all @c count threads have called @c wait and
  /// then allow all the caller threads to continue in parallel.
  ///
  /// @retval 0 after successfully waiting for all threads to wait.
  /// @retval -1 if an error occurs or the barrier is shut
  /// down (@sa shutdown ()).
  int wait (void);

  /// Shut the barrier down, aborting the wait of all waiting threads.
  /// Any threads waiting on the barrier when it is shut down will return with
  /// value -1, errno ESHUTDOWN.
  ///
  /// @retval 0 for success, -1 if already shut down.
  ///
  /// @since ACE beta 5.4.9.
  int shutdown (void);

  /// Dump the state of an object.
  void dump (void) const;

  /// Declare the dynamic allocation hooks.
  ACE_ALLOC_HOOK_DECLARE;

protected:
  /// Serialize access to the barrier state.
  ACE_Thread_Mutex lock_;

  /// Either 0 or 1, depending on whether we are the first generation
  /// of waiters or the next generation of waiters.
  int current_generation_;

  /// Total number of threads that can be waiting at any one time.
  int count_;

  /**
   * We keep two @c sub_barriers, one for the first "generation" of
   * waiters, and one for the next "generation" of waiters.  This
   * efficiently solves the problem of what to do if all the first
   * generation waiters don't leave the barrier before one of the
   * threads calls wait() again (i.e., starts up the next generation
   * barrier).
   */
  ACE_Sub_Barrier sub_barrier_1_;
  ACE_Sub_Barrier sub_barrier_2_;
  ACE_Sub_Barrier *sub_barrier_[2];

private:
  // = Prevent assignment and initialization.
  void operator= (const ACE_Barrier &);
  ACE_Barrier (const ACE_Barrier &);
};

/**
 * @class ACE_Thread_Barrier
 *
 * @brief Implements "barrier synchronization" using ACE_Thread_Mutexes!
 *
 * This class is just a simple wrapper for ACE_Barrier that
 * selects the USYNC_THREAD variant for the locks.
 */
class ACE_Export ACE_Thread_Barrier : public ACE_Barrier
{
public:
  /// Create a Thread_Barrier, passing in the optional @a name.
  ACE_Thread_Barrier (unsigned int count, const ACE_TCHAR *name = 0);

  /// Default destructor.
  ~ACE_Thread_Barrier (void);

  /// Dump the state of an object.
  void dump (void) const;

  /// Declare the dynamic allocation hooks.
  ACE_ALLOC_HOOK_DECLARE;
};

ACE_END_VERSIONED_NAMESPACE_DECL

#if defined (__ACE_INLINE__)
#include "ace/Barrier.inl"
#endif /* __ACE_INLINE__ */

#endif /* !ACE_HAS_THREADS */

#include /**/ "ace/post.h"
#endif /* ACE_BARRIER_H */