source: rrlib_thread/tLock.h @ 8:5a3625dd40e8

Last change on this file since 8:5a3625dd40e8 was 8:5a3625dd40e8, checked in by Max Reichardt <mreichardt@…>, 6 years ago

Added TryLock() function(ality) to class tLock. Fixed small issues in thread class.

File size: 9.2 KB
Line 
1//
2// You received this file as part of RRLib
3// Robotics Research Library
4//
5// Copyright (C) Finroc GbR (finroc.org)
6//
7// This program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public License
9// as published by the Free Software Foundation; either version 2
10// of the License, or (at your option) any later version.
11//
12// This program 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
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program; if not, write to the Free Software
19// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20//
21//----------------------------------------------------------------------
22/*!\file    rrlib/thread/tLock.h
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2012-07-04
27 *
28 * \brief   Contains tLock
29 *
30 * \b tLock
31 *
32 * Lock for all mutex classes in rrlib_thread
33 *
34 * (Wraps std::unique_lock for different mutex types.
35 *  Additionally enforces correct lock order if #define
36 *  RRLIB_THREAD_ENFORCE_LOCK_ORDER is enabled)
37 *
38 */
39//----------------------------------------------------------------------
40#ifndef __rrlib__thread__tLock_h__
41#define __rrlib__thread__tLock_h__
42
43//----------------------------------------------------------------------
44// External includes (system with <>, local with "")
45//----------------------------------------------------------------------
46#include <mutex>
47
48//----------------------------------------------------------------------
49// Internal includes with ""
50//----------------------------------------------------------------------
51#include "rrlib/thread/tNoMutex.h"
52#include "rrlib/thread/tOrderedMutex.h"
53#include "rrlib/thread/tRecursiveMutex.h"
54#include "rrlib/thread/internal/tLockStack.h"
55
56//----------------------------------------------------------------------
57// Namespace declaration
58//----------------------------------------------------------------------
59namespace rrlib
60{
61namespace thread
62{
63
64//----------------------------------------------------------------------
65// Forward declarations / typedefs / enums
66//----------------------------------------------------------------------
67
68/*
69#ifndef _FINROC_SYSTEM_INSTALLATION_PRESENT_
70#ifndef NDEBUG
71#define RRLIB_THREAD_ENFORCE_LOCK_ORDER
72#endif
73#endif
74*/
75
76//----------------------------------------------------------------------
77// Class declaration
78//----------------------------------------------------------------------
79//! Unique Lock
80/*!
81 * Lock for all mutex classes in rrlib_thread
82 *
83 * (Wraps std::unique_lock for different mutex types.
84 *  Additionally enforces correct lock order if #define
85 *  RRLIB_THREAD_ENFORCE_LOCK_ORDER is enabled)
86 */
87class tLock : boost::noncopyable
88{
89  friend class internal::tLockStack;
90
91//----------------------------------------------------------------------
92// Public methods and typedefs
93//----------------------------------------------------------------------
94public:
95
96#ifndef RRLIB_SINGLE_THREADED
97
98  /*! Creates lock not related to any mutex (cannot be locked) */
99  explicit tLock() :
100    simple_lock(),
101    recursive_lock(),
102    locked_ordered(NULL),
103    locked_simple(NULL)
104  {}
105
106  /*!
107   * \param mutex Mutex to lock
108   * \param immediately_lock Immediately lock mutex on construction of this lock?
109   * (If this is false, Lock() or TryLock() can be called later to acquire lock)
110   */
111  template <typename TMutex>
112  inline explicit tLock(const TMutex& mutex, bool immediately_lock = true) :
113    simple_lock(),
114    recursive_lock(),
115    locked_ordered(GetLockedOrdered(mutex)),
116    locked_simple(GetLockedSimple(mutex))
117  {
118    if (immediately_lock)
119    {
120      Lock(mutex);
121    }
122  }
123
124  /*! move constructor */
125  explicit tLock(tLock && other) :
126    simple_lock(),
127    recursive_lock(),
128    locked_ordered(NULL),
129    locked_simple(NULL)
130  {
131    std::swap(simple_lock, other.simple_lock);
132    std::swap(recursive_lock, other.recursive_lock);
133    std::swap(locked_ordered, other.locked_ordered);
134    std::swap(locked_simple, other.locked_simple);
135  }
136
137  /*! move assignment */
138  tLock& operator=(tLock && other)
139  {
140    std::swap(simple_lock, other.simple_lock);
141    std::swap(recursive_lock, other.recursive_lock);
142    std::swap(locked_ordered, other.locked_ordered);
143    std::swap(locked_simple, other.locked_simple);
144    return *this;
145  }
146
147  ~tLock()
148  {
149#ifdef RRLIB_THREAD_ENFORCE_LOCK_ORDER
150    if ((locked_simple && simple_lock.owns_lock()) || (locked_ordered && recursive_lock.owns_lock()))
151    {
152      bool ok = (internal::tLockStack::Pop() == this);
153      assert(ok);
154    }
155#endif
156  }
157
158  /*!
159   * \return Wrapped lock (only exists as long as this object!)
160   */
161  std::unique_lock<std::mutex>& GetSimpleLock()
162  {
163    return simple_lock;
164  }
165
166  /*!
167   * \param mutex Mutex (either tOrderedMutex or tMutex)
168   *
169   * return Is specified mutex currently locked by this lock?
170   */
171  bool IsLocked(const tMutex& mutex) const
172  {
173    return &mutex == locked_simple && simple_lock.owns_lock();
174  }
175
176  /*!
177   * Lock (again)
178   */
179  inline void Lock()
180  {
181    assert(((!simple_lock.owns_lock()) && (!(recursive_lock.owns_lock()))) && "Unlock before calling lock()");
182    if (locked_simple)
183    {
184      Lock(*locked_simple);
185    }
186    else if (locked_ordered)
187    {
188      Lock(static_cast<const tRecursiveMutex&>(*locked_ordered));
189    }
190  }
191
192  /*!
193   * Tries to acquire lock on mutex (does not block)
194   *
195   * \return True, if lock could be acquired
196   */
197  inline bool TryLock()
198  {
199    assert(((!simple_lock.owns_lock()) && (!(recursive_lock.owns_lock()))) && "Unlock before calling lock()");
200    if (locked_simple)
201    {
202      return TryLock(*locked_simple);
203    }
204    else if (locked_ordered)
205    {
206      return TryLock(static_cast<const tRecursiveMutex&>(*locked_ordered));
207    }
208    return true;
209  }
210
211  /*!
212   * Unlock/Release lock
213   */
214  void Unlock()
215  {
216    if (simple_lock.owns_lock())
217    {
218#ifdef RRLIB_THREAD_ENFORCE_LOCK_ORDER
219      bool ok = (internal::tLockStack::Pop() == this);
220      assert(ok);
221#endif
222      simple_lock.unlock();
223    }
224    else if (recursive_lock.owns_lock())
225    {
226#ifdef RRLIB_THREAD_ENFORCE_LOCK_ORDER
227      bool ok = (internal::tLockStack::Pop() == this);
228      assert(ok);
229#endif
230      recursive_lock.unlock();
231    }
232  }
233
234#else
235
236  tLock() {}
237
238  template <typename T>
239  tLock(const T& mutex) {}
240
241  template <typename T1, typename T2>
242  tLock(const T& mutex, T2 parameter) {}
243
244  ~tLock() {}
245
246#endif
247
248
249//----------------------------------------------------------------------
250// Private fields and methods
251//----------------------------------------------------------------------
252private:
253
254#ifndef RRLIB_SINGLE_THREADED
255
256  /*! wrapped locks */
257  std::unique_lock<std::mutex> simple_lock;
258  std::unique_lock<std::recursive_mutex> recursive_lock;
259
260  /*! Raw pointer(s) to mutex that was acquired by this lock */
261  const tOrderedMutexBaseClass* locked_ordered;
262  const tMutex* locked_simple;
263
264
265  // Internal helper methods to handle different variants of mutexes uniformly in constructors
266
267  inline const tOrderedMutexBaseClass* GetLockedOrdered(const tMutex& mutex)
268  {
269    return NULL;
270  }
271  inline const tOrderedMutexBaseClass* GetLockedOrdered(const tNoMutex& mutex)
272  {
273    return NULL;
274  }
275  inline const tOrderedMutexBaseClass* GetLockedOrdered(const tOrderedMutex& mutex)
276  {
277    return &mutex;
278  }
279  inline const tOrderedMutexBaseClass* GetLockedOrdered(const tRecursiveMutex& mutex)
280  {
281    return &mutex;
282  }
283  inline const tMutex* GetLockedSimple(const tMutex& mutex)
284  {
285    return &mutex;
286  }
287  inline const tMutex* GetLockedSimple(const tNoMutex& mutex)
288  {
289    return NULL;
290  }
291  inline const tMutex* GetLockedSimple(const tOrderedMutex& mutex)
292  {
293    return &mutex;
294  }
295  inline const tMutex* GetLockedSimple(const tRecursiveMutex& mutex)
296  {
297    return NULL;
298  }
299
300  inline void Lock(const tNoMutex& mutex) {}
301  inline void Lock(const tMutex& mutex)
302  {
303#ifdef RRLIB_THREAD_ENFORCE_LOCK_ORDER
304    internal::tLockStack::Push(this);
305#endif
306    simple_lock = std::unique_lock<std::mutex>(mutex.wrapped);
307  }
308  inline void Lock(const tRecursiveMutex& mutex)
309  {
310#ifdef RRLIB_THREAD_ENFORCE_LOCK_ORDER
311    internal::tLockStack::Push(this);
312#endif
313    recursive_lock = std::unique_lock<std::recursive_mutex>(mutex.wrapped);
314  }
315
316  inline bool TryLock(const tNoMutex& mutex)
317  {
318    return true;
319  }
320  inline bool TryLock(const tMutex& mutex)
321  {
322    simple_lock = std::unique_lock<std::mutex>(mutex.wrapped, std::defer_lock_t());
323    bool locked = simple_lock.try_lock();
324    if (locked)
325    {
326#ifdef RRLIB_THREAD_ENFORCE_LOCK_ORDER
327      internal::tLockStack::Push(this);
328#endif
329    }
330    return locked;
331  }
332  inline bool TryLock(const tRecursiveMutex& mutex)
333  {
334    recursive_lock = std::unique_lock<std::recursive_mutex>(mutex.wrapped, std::defer_lock_t());
335    bool locked = recursive_lock.try_lock();
336    if (locked)
337    {
338#ifdef RRLIB_THREAD_ENFORCE_LOCK_ORDER
339      internal::tLockStack::Push(this);
340#endif
341    }
342    return locked;
343  }
344
345#endif
346
347
348};
349
350//----------------------------------------------------------------------
351// End of namespace declaration
352//----------------------------------------------------------------------
353}
354}
355
356
357#endif
Note: See TracBrowser for help on using the repository browser.