basic implementation of fast_signal, enqueueing in the event_loop doesn't work yet.
[beacon-ss.git] / beacon / synchronizer.hpp
bloba75ddba851d4d5c5cd12a51b4e8b6ab5d06d7d83
1 /**
2 * beacon
3 * Author: Lukas Krejci <krejci.l@centrum.cz>, (C) 2008
4 * Copyright: See COPYING file that comes with this distribution
5 */
7 #ifndef BEACON_SYNCHRONIZER_H
8 #define BEACON_SYNCHRONIZER_H
10 #include <beacon/detail/quick_wait.hpp>
11 #include <utility>
13 namespace beacon {
15 namespace detail {
17 /**
18 * This class is used to synchronize access to 2 objects
19 * that need to ensure that each other is available in a
20 * multithread safe manner.
21 * Do not use it directly, Use {@link create_synchronizers}
22 * function instead.
24 struct synchronizer {
26 public:
27 synchronizer() : _active(2), _locked(AO_TS_INITIALIZER) {
30 ~synchronizer() {
31 unlock();
34 void lock() {
35 wait(_locked);
38 void unlock() {
39 notify(_locked);
42 /**
43 * @return the number of active delegates left after this call.
45 unsigned release_one() {
46 unsigned left = --_active;
47 if (left == 0) {
48 delete this;
51 return left;
54 /**
55 * @return the number of active delegates. Never returns 0, because
56 * this instance automatically destroys itself when the delegate count
57 * reaches 0.
59 unsigned active() {
60 return _active;
62 private:
64 //no copies
65 synchronizer(synchronizer const &) : _active(2), _locked(AO_TS_INITIALIZER) {}
66 synchronizer const & operator=(synchronizer const &) {
67 return *this;
70 unsigned _active;
71 volatile AO_TS_t _locked;
74 } //namespace detail
76 /**
77 * Two instances of this class are returned from {@link create_synchronizers} function.
78 * Each such delegate is intended to be used by one of the objects passed to the function.
79 * A delegate is intended to be used from a single thread.
81 template<typename OtherType>
82 class synchronizer_delegate {
84 public:
85 synchronizer_delegate(detail::synchronizer & sync, OtherType other) :
86 _sync(sync),
87 _other(other),
88 _bound(true),
89 _locked(false) {}
91 /**
92 * Calls @c release.
94 ~synchronizer_delegate() {
95 release();
98 /**
99 * Locks the synchronizer. If the other object from the pair
100 * created by the {@link create_synchronizers} function call this method
101 * on its synchronizer_delegate, it will block until this object calls
102 * the unlock method.
104 void lock() {
105 if (_bound) {
106 _sync.lock();
107 _locked = true;
112 * Unlocks the synchronizer. It is an error to call this if the synchronizer
113 * has not been locked before.
115 void unlock() {
116 if (_bound) {
117 _sync.unlock();
118 _locked = false;
123 * Releases this delegate from the synchronizer. Any subsequent calls to
124 * any of this instance's methods will have no effect. {@link other} method
125 * will return 0. If this delegate locked the synchronizer before, it is
126 * silently unlocked by this method, i.e. there's no need to call unlock
127 * after release (it would have no effect anyway).
129 void release() {
130 if (_bound) {
131 if (!_locked) {
132 lock();
134 //if release_one returns 0, it destroyed and unlocked itself
135 //automatically.
136 if (_sync.release_one() > 0) {
137 unlock();
139 _bound = false;
140 _other = 0;
145 * @return the "other" object that uses the same synchronizer or null if the
146 * object no longer exists.
148 OtherType other() {
149 if (_bound && _sync.active() > 1) {
150 return _other;
152 return 0;
154 private:
156 //no copying
157 synchronizer_delegate(synchronizer_delegate<OtherType> const &) {}
158 synchronizer_delegate<OtherType> const & operator=(synchronizer_delegate<OtherType> const &){}
160 detail::synchronizer & _sync;
161 OtherType _other;
162 bool _bound;
163 bool _locked;
167 * This function creates two {@link synchronizer_delegate}s each intended to be used
168 * by 1 of the objects passed.
170 template<typename T1, typename T2>
171 std::pair<synchronizer_delegate<T2> *, synchronizer_delegate<T1> * > create_synchronizers(
172 T1 o1,
173 T2 o2) {
175 detail::synchronizer * sync = new detail::synchronizer;
177 return std::pair<synchronizer_delegate<T2> *, synchronizer_delegate<T1> * >(
178 new synchronizer_delegate<T2>(*sync, o2),
179 new synchronizer_delegate<T1>(*sync, o1));
182 } //namespace
184 #endif