sigx++  2.0.1
lock_acquirer.h
Go to the documentation of this file.
1 #ifndef _SIGX_LOCK_ACQUIRER_H_
2 #define _SIGX_LOCK_ACQUIRER_H_
3 
4 /*
5  * Copyright 2006 Klaus Triendl
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the Free
19  * Software Foundation, 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21 */
22 
23 /*
24  * Inspired by Andrei Alexandrescu's article "volatile - Multithreaded
25  * Programmer's Best Friend":
26  * http://www.ddj.com/dept/cpp/184403766
27  */
28 
29 #include <tr1/type_traits>
30 #include <boost/mpl/eval_if.hpp>
31 #include <boost/mpl/identity.hpp>
32 #include <sigx/noncopyable.h>
33 //#include <sigx/nonheapallocatable.h>
35 #include <sigx/lockable_fwddecl.h>
36 #include <sigx/choose_lock.h>
37 
38 
39 namespace sigx
40 {
41 
87 template<locking_policy I_policy, typename T_type, typename T_mutex, typename T_islockable>
88 class lock_acquirer: noncopyable/*, nonheapallocatable*/, nonpointeraliasing
89 {
90 protected:
91  typedef T_type acquired_type;
92  typedef T_mutex mutex_type;
93  // value_type = acquired_type with top-level reference stripped off
94  typedef typename std::tr1::remove_reference<acquired_type>::type value_type;
95  // const_or_value_type = unchanged value_type if policy is writelock, const value_type if readlock
96  typedef typename boost::mpl::eval_if_c<
97  I_policy == readlock,
98  std::tr1::add_const<value_type>,
99  boost::mpl::identity<value_type>
101  typedef typename std::tr1::add_reference<typename std::tr1::add_volatile<value_type>::type>::type volatile_reference_type;
102  typedef typename std::tr1::add_reference<typename std::tr1::remove_volatile<const_or_value_type>::type>::type reference_type;
103 
109  friend reference_type
111  {
112  return l.access_acquiree();
113  }
114 
115 
116 public:
124  m_lock(_a_mutex),
125  // volatile_cast
126  m_acquiree(const_cast<reference_type>(_a_value))
127  {}
132  template<typename T_lockfwd_arg1>
133  lock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex, T_lockfwd_arg1 lockfwd_arg1):
134  m_lock(_a_mutex, lockfwd_arg1),
135  // volatile_cast
136  m_acquiree(const_cast<reference_type>(_a_value))
137  {}
138 
139 
140 protected:
144  {
145  return m_acquiree;
146  }
147 
148 
149 protected:
152  typename choose_lock<mutex_type, I_policy>::type m_lock;
153 
157 };
158 
159 
160 
161 template<typename T_type, typename T_mutex, typename T_islockable>
162 class writelock_acquirer: public lock_acquirer<writelock, T_type, T_mutex, T_islockable>
163 {
165  typedef typename parent_type::mutex_type mutex_type;
166  typedef typename parent_type::volatile_reference_type volatile_reference_type;
167 
168 public:
172  writelock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex):
173  parent_type(_a_value, _a_mutex)
174  {}
179  template<typename T_lockfwd_arg1>
180  writelock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex, T_lockfwd_arg1 lockfwd_arg1):
181  parent_type(_a_value, _a_mutex, lockfwd_arg1)
182  {}
183 };
184 
185 template<typename T_type, typename T_mutex, typename T_islockable>
186 class readlock_acquirer: public lock_acquirer<readlock, T_type, T_mutex, T_islockable>
187 {
189  typedef typename parent_type::mutex_type mutex_type;
190  typedef typename parent_type::volatile_reference_type volatile_reference_type;
191 
192 public:
197  parent_type(_a_value, _a_mutex)
198  {}
203  template<typename T_lockfwd_arg1>
204  readlock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex, T_lockfwd_arg1 lockfwd_arg1):
205  parent_type(_a_value, _a_mutex, lockfwd_arg1)
206  {}
207 };
208 
241 template<locking_policy I_policy, typename T_type, typename T_mutex>
242 class lock_acquirer<I_policy, T_type, T_mutex, std::tr1::true_type>:
243  // derive from lock_acquirer for the locked type (which is lockable::acquired_type);
244  public lock_acquirer<
245  I_policy,
246  // if the lockable is const ...
247  typename boost::mpl::eval_if<
248  std::tr1::is_const<T_type>,
249  // ... then transfer constness to the type to protect (constness for lockables and the locked type is transitive)
250  std::tr1::add_const<typename T_type::acquired_type>,
251  // ... otherwise keep it as specified
252  boost::mpl::identity<typename T_type::acquired_type>
253  >::type,
254  T_mutex
255  // let compiler deduce whether acquired_type is again a lockable
256  /*, std::tr1::false_type*/
257  >
258 {
259  typedef lock_acquirer<
260  I_policy,
261  typename boost::mpl::eval_if<
262  std::tr1::is_const<T_type>,
263  std::tr1::add_const<typename T_type::acquired_type>,
264  boost::mpl::identity<typename T_type::acquired_type>
265  >::type,
266  T_mutex
267  /*, std::tr1::false_type*/
268  > parent_type;
269  typedef T_type lockable_type;
270 
271 
272 public:
276  explicit lock_acquirer(lockable_type& _a_lockable):
277  parent_type(_a_lockable.access_volatile(), _a_lockable.mutex())
278  {}
283  template<typename T_lockfwd_arg1>
284  lock_acquirer(lockable_type& _a_lockable, T_lockfwd_arg1 lockfwd_arg1):
285  parent_type(_a_lockable.access_volatile(), _a_lockable.mutex(), lockfwd_arg1)
286  {}
287 };
288 
289 
292 template<typename T_type, typename T_mutex>
293 class writelock_acquirer<T_type, T_mutex, std::tr1::true_type>: public lock_acquirer<writelock, T_type, T_mutex, std::tr1::true_type>
294 {
296  typedef T_type lockable_type;
297 
298 
299 public:
303  explicit writelock_acquirer(lockable_type& _a_lockable):
304  parent_type(_a_lockable)
305  {}
310  template<typename T_lockfwd_arg1>
311  writelock_acquirer(lockable_type& _a_lockable, T_lockfwd_arg1 lockfwd_arg1):
312  parent_type(_a_lockable, lockfwd_arg1)
313  {}
314 };
315 
316 
319 template<typename T_type, typename T_mutex>
320 class readlock_acquirer<T_type, T_mutex, std::tr1::true_type>: public lock_acquirer<readlock, T_type, T_mutex, std::tr1::true_type>
321 {
323  typedef T_type lockable_type;
324 
325 
326 public:
330  explicit readlock_acquirer(lockable_type& _a_lockable):
331  parent_type(_a_lockable)
332  {}
337  template<typename T_lockfwd_arg1>
338  readlock_acquirer(lockable_type& _a_lockable, T_lockfwd_arg1 lockfwd_arg1):
339  parent_type(_a_lockable, lockfwd_arg1)
340  {}
341 };
342 
343 
344 // @addtogroup threadsafety
348 } // namespace mbox
349 
350 
351 #endif // end file guard