source: rrlib_thread/tLock.h @ 1:e3d42f26a8cf

Last change on this file since 1:e3d42f26a8cf was 1:e3d42f26a8cf, checked in by Max Reichardt <mreichardt@…>, 7 years ago

Fixed lock and lock stack class so that we actually see an error message if someone attempts to lock plain mutex twice.

File size: 6.1 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 */
35//----------------------------------------------------------------------
36#ifndef __rrlib__thread__tLock_h__
37#define __rrlib__thread__tLock_h__
38
39//----------------------------------------------------------------------
40// External includes (system with <>, local with "")
41//----------------------------------------------------------------------
42#include <mutex>
43
44//----------------------------------------------------------------------
45// Internal includes with ""
46//----------------------------------------------------------------------
47#include "rrlib/thread/tNoMutex.h"
48#include "rrlib/thread/tOrderedMutex.h"
49#include "rrlib/thread/tRecursiveMutex.h"
50#include "rrlib/thread/internal/tLockStack.h"
51
52//----------------------------------------------------------------------
53// Namespace declaration
54//----------------------------------------------------------------------
55namespace rrlib
56{
57namespace thread
58{
59
60//----------------------------------------------------------------------
61// Forward declarations / typedefs / enums
62//----------------------------------------------------------------------
63
64/*
65#ifndef _FINROC_SYSTEM_INSTALLATION_PRESENT_
66#ifndef NDEBUG
67#define RRLIB_THREAD_ENFORCE_LOCK_ORDER
68#endif
69#endif
70*/
71
72//----------------------------------------------------------------------
73// Class declaration
74//----------------------------------------------------------------------
75//! Lock
76/*!
77 * Lock for all mutex classes in rrlib_thread
78 */
79class tLock : boost::noncopyable
80{
81  friend class internal::tLockStack;
82
83//----------------------------------------------------------------------
84// Public methods and typedefs
85//----------------------------------------------------------------------
86public:
87
88#ifndef RRLIB_SINGLE_THREADED
89
90  explicit tLock(const tMutex& mutex) :
91    simple_lock(),
92    recursive_lock(),
93    locked_ordered(NULL),
94    locked_simple(&mutex)
95  {
96#ifdef RRLIB_THREAD_ENFORCE_LOCK_ORDER
97    internal::tLockStack::Push(this);
98#endif
99    simple_lock = std::unique_lock<std::mutex>(mutex.wrapped);
100  }
101
102  explicit tLock(const tNoMutex& mutex) :
103    simple_lock(),
104    recursive_lock(),
105    locked_ordered(NULL),
106    locked_simple(NULL)
107  {
108  }
109
110  explicit tLock(const tOrderedMutex& mutex) :
111    simple_lock(),
112    recursive_lock(),
113    locked_ordered(&mutex),
114    locked_simple(&mutex)
115  {
116#ifdef RRLIB_THREAD_ENFORCE_LOCK_ORDER
117    internal::tLockStack::Push(this);
118#endif
119    simple_lock = std::unique_lock<std::mutex>(mutex.wrapped);
120  }
121
122  explicit tLock(const tRecursiveMutex& mutex) :
123    simple_lock(),
124    recursive_lock(),
125    locked_ordered(&mutex),
126    locked_simple()
127  {
128#ifdef RRLIB_THREAD_ENFORCE_LOCK_ORDER
129    internal::tLockStack::Push(this);
130#endif
131    recursive_lock = std::unique_lock<std::recursive_mutex>(mutex.wrapped);
132  }
133
134  ~tLock()
135  {
136#ifdef RRLIB_THREAD_ENFORCE_LOCK_ORDER
137    if ((locked_simple && simple_lock.owns_lock()) || (locked_ordered && recursive_lock.owns_lock()))
138    {
139      bool ok = (internal::tLockStack::Pop() == this);
140      assert(ok);
141    }
142#endif
143  }
144
145  /*!
146   * \return Wrapped lock (only exists as long as this object!)
147   */
148  std::unique_lock<std::mutex>& GetSimpleLock()
149  {
150    return simple_lock;
151  }
152
153#else
154
155  template <typename T>
156  tLock(const T& mutex) {}
157
158  ~tLock() {}
159
160#endif
161
162  /*!
163   * \param mutex Mutex (either tOrderedMutex or tMutex)
164   *
165   * return Is specified mutex currently locked by this lock?
166   */
167  bool IsLocked(const tMutex& mutex) const
168  {
169    return &mutex == locked_simple && simple_lock.owns_lock();
170  }
171
172  /*!
173   * Unlock/Release lock
174   */
175  void Unlock()
176  {
177    if (simple_lock.owns_lock())
178    {
179#ifdef RRLIB_THREAD_ENFORCE_LOCK_ORDER
180      bool ok = (internal::tLockStack::Pop() == this);
181      assert(ok);
182#endif
183      simple_lock.unlock();
184    }
185    else if (recursive_lock.owns_lock())
186    {
187#ifdef RRLIB_THREAD_ENFORCE_LOCK_ORDER
188      bool ok = (internal::tLockStack::Pop() == this);
189      assert(ok);
190#endif
191      recursive_lock.unlock();
192    }
193  }
194
195  /*!
196   * Lock (again)
197   */
198  void Lock()
199  {
200    assert(((!simple_lock.owns_lock()) && (!(recursive_lock.owns_lock()))) && "Unlock before calling lock()");
201    if (locked_simple)
202    {
203#ifdef RRLIB_THREAD_ENFORCE_LOCK_ORDER
204      internal::tLockStack::Push(this);
205#endif
206      simple_lock.lock();
207    }
208    else if (locked_ordered)
209    {
210#ifdef RRLIB_THREAD_ENFORCE_LOCK_ORDER
211      internal::tLockStack::Push(this);
212#endif
213      recursive_lock.lock();
214    }
215  }
216
217//----------------------------------------------------------------------
218// Private fields and methods
219//----------------------------------------------------------------------
220private:
221
222#ifndef RRLIB_SINGLE_THREADED
223
224  /*! wrapped locks */
225  std::unique_lock<std::mutex> simple_lock;
226  std::unique_lock<std::recursive_mutex> recursive_lock;
227
228  /*! Raw pointer(s) to mutex that was acquired by this lock */
229  const tOrderedMutexBaseClass* locked_ordered;
230  const tMutex* locked_simple;
231
232#endif
233};
234
235//----------------------------------------------------------------------
236// End of namespace declaration
237//----------------------------------------------------------------------
238}
239}
240
241
242#endif
Note: See TracBrowser for help on using the repository browser.