Fawkes API  Fawkes Development Version
barrier.cpp
1 
2 /***************************************************************************
3  * barrier.cpp - Barrier
4  *
5  * Created: Thu Sep 15 00:33:13 2006
6  * Copyright 2006-2009 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <core/threading/barrier.h>
25 #include <core/exception.h>
26 
27 #include <pthread.h>
28 #include <unistd.h>
29 
30 // cf. http://people.redhat.com/drepper/posix-option-groups.html
31 #if defined(_POSIX_BARRIERS) && (_POSIX_BARRIERS - 200112L) >= 0
32 # define USE_POSIX_BARRIERS
33 #else
34 # undef USE_POSIX_BARRIERS
35 # include <core/threading/mutex.h>
36 # include <core/threading/wait_condition.h>
37 #endif
38 
39 namespace fawkes {
40 
41 
42 /// @cond INTERNALS
43 class BarrierData
44 {
45  public:
46 #ifdef USE_POSIX_BARRIERS
47  pthread_barrier_t barrier;
48 #else
49  BarrierData() : threads_left(0), mutex(), waitcond(&mutex) {}
50 
51  unsigned int threads_left;
52  Mutex mutex;
53  WaitCondition waitcond;
54 #endif
55 };
56 /// @endcond
57 
58 
59 /** @class Barrier core/threading/barrier.h
60  * A barrier is a synchronization tool which blocks until a given number of
61  * threads have reached the barrier.
62  *
63  * Consider you have three threads all doing work. In the end you have to merge
64  * their results. For this you need a point where all threads are finished. Of
65  * course you don't want another thread waiting and periodically checking if
66  * the other threads are finished, that will loose time - processing time and
67  * the time that passed between the threads being finished and the time when
68  * the controller checked again.
69  *
70  * For this problem we have a barrier. You initialize the barrier with the
71  * number of threads to wait for and then wait in all threads at a specific
72  * point. After this one of the threads can merge the result (and the others
73  * may wait for another "go-on barrier".
74  *
75  * The code in the thread would be
76  * @code
77  * virtual void run()
78  * {
79  * forever {
80  * do_something();
81  * result_barrier->wait();
82  * if ( master_thread ) {
83  * merge_results();
84  * }
85  * goon_barrier->wait();
86  * }
87  * }
88  * @endcode
89  *
90  * The threads would all get a reference to the same barriers and one would
91  * have master thread to be true.
92  *
93  * After the barrier has been passed (count threads waited) the barrier is
94  * reset automatically and can be re-used with the same amount of barrier
95  * waiters.
96  *
97  * The implementation of Barrier takes into account that PThread barriers are
98  * optional in POSIX. If barriers are not available they are emulated using a
99  * wait condition. Note however that on systems that do have both, barriers and
100  * wait conditions it has been observed that in a typical barrier scenario the
101  * POSIX barriers perform much better in many situations than a wait condition
102  * (processes tend to be rescheduled immediately if a barrier is reached, while
103  * with a wait condition they are rescheduled with lower priority and thus they
104  * delay may increase on a loaded system). Because of this on systems without
105  * real POSIX barriers the performance may be not as good as is expected.
106  *
107  * @ingroup Threading
108  * @author Tim Niemueller
109  */
110 
111 
112 /** Constructor
113  * @param count the number of threads to wait for
114  */
115 Barrier::Barrier(unsigned int count)
116 {
117  _count = count;
118  if ( _count == 0 ) {
119  throw Exception("Barrier count must be at least 1");
120  }
121  barrier_data = new BarrierData();
122 #ifdef USE_POSIX_BARRIERS
123  pthread_barrier_init( &(barrier_data->barrier), NULL, _count );
124 #else
125  barrier_data->threads_left = _count;
126 #endif
127 }
128 
129 
130 /** Protected Constructor.
131  * Does not initialize any internal structures other than setting them to 0.
132  */
134 {
135  _count = 0;
136  barrier_data = NULL;
137 }
138 
139 
140 /** Destructor */
142 {
143  if (barrier_data) {
144 #ifdef USE_POSIX_BARRIERS
145  pthread_barrier_destroy( &(barrier_data->barrier) );
146 #endif
147  delete barrier_data;
148  }
149 }
150 
151 
152 /** Wait for other threads.
153  * This method will block until as many threads have called wait as you have
154  * given count to the constructor.
155  */
156 void
158 {
159 #ifdef USE_POSIX_BARRIERS
160  pthread_barrier_wait( &(barrier_data->barrier) );
161 #else
162  barrier_data->mutex.lock();
163 
164  if ( --barrier_data->threads_left == 0 ) {
165  barrier_data->threads_left = _count;
166  barrier_data->mutex.unlock();
167  barrier_data->waitcond.wake_all();
168  } else {
169  barrier_data->waitcond.wait();
170  barrier_data->mutex.unlock();
171  }
172 
173 #endif
174 }
175 
176 
177 /** Get number of threads this barrier will wait for.
178  * @return number of threads this barrier will wait for.
179  */
180 unsigned int
182 {
183  return _count;
184 }
185 
186 
187 } // end namespace fawkes
unsigned int count()
Get number of threads this barrier will wait for.
Definition: barrier.cpp:181
Fawkes library namespace.
virtual void wait()
Wait for other threads.
Definition: barrier.cpp:157
Barrier()
Protected Constructor.
Definition: barrier.cpp:133
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual ~Barrier()
Destructor.
Definition: barrier.cpp:141