QtBase  v6.3.1
qmutex.h
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QMUTEX_H
41 #define QMUTEX_H
42 
43 #include <QtCore/qglobal.h>
44 #include <QtCore/qatomic.h>
45 #include <new>
46 
47 #if __has_include(<chrono>)
48 # include <chrono>
49 # include <limits>
50 #endif
51 
52 class tst_QMutex;
53 
55 
56 
57 #if QT_CONFIG(thread) || defined(Q_CLANG_QDOC)
58 
59 #ifdef Q_OS_LINUX
60 # define QT_MUTEX_LOCK_NOEXCEPT noexcept
61 #else
62 # define QT_MUTEX_LOCK_NOEXCEPT
63 #endif
64 
65 class QMutex;
66 class QRecursiveMutex;
67 class QMutexPrivate;
68 
69 #if __has_include(<chrono>)
70 namespace QtPrivate
71 {
72  template<class Rep, class Period>
73  static int convertToMilliseconds(std::chrono::duration<Rep, Period> duration)
74  {
75  // N4606 § 30.4.1.3.5 [thread.timedmutex.requirements] specifies that a
76  // duration less than or equal to duration.zero() shall result in a
77  // try_lock, unlike QMutex's tryLock with a negative duration which
78  // results in a lock.
79 
80  if (duration <= duration.zero())
81  return 0;
82 
83  // when converting from 'duration' to milliseconds, make sure that
84  // the result is not shorter than 'duration':
85  std::chrono::milliseconds wait = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
86  if (wait < duration)
87  wait += std::chrono::milliseconds(1);
88  Q_ASSERT(wait >= duration);
89  const auto ms = wait.count();
90  const auto maxInt = (std::numeric_limits<int>::max)();
91 
92  return ms < maxInt ? int(ms) : maxInt;
93  }
94 }
95 #endif
96 
97 class Q_CORE_EXPORT QBasicMutex
98 {
100 public:
101  constexpr QBasicMutex()
102  : d_ptr(nullptr)
103  {}
104 
105  // BasicLockable concept
106  inline void lock() QT_MUTEX_LOCK_NOEXCEPT {
107  if (!fastTryLock())
108  lockInternal();
109  }
110 
111  // BasicLockable concept
112  inline void unlock() noexcept {
113  Q_ASSERT(d_ptr.loadRelaxed()); //mutex must be locked
114  if (!fastTryUnlock())
115  unlockInternal();
116  }
117 
118  bool tryLock() noexcept {
119  return fastTryLock();
120  }
121 
122  // Lockable concept
123  bool try_lock() noexcept { return tryLock(); }
124 
125 private:
126  inline bool fastTryLock() noexcept {
127  return d_ptr.testAndSetAcquire(nullptr, dummyLocked());
128  }
129  inline bool fastTryUnlock() noexcept {
130  return d_ptr.testAndSetRelease(dummyLocked(), nullptr);
131  }
132 
133  void lockInternal() QT_MUTEX_LOCK_NOEXCEPT;
134  bool lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT;
135  void unlockInternal() noexcept;
136  void destroyInternal(QMutexPrivate *d);
137 
139  static inline QMutexPrivate *dummyLocked() {
140  return reinterpret_cast<QMutexPrivate *>(quintptr(1));
141  }
142 
143  friend class QMutex;
144  friend class QMutexPrivate;
145 };
146 
147 class Q_CORE_EXPORT QMutex : public QBasicMutex
148 {
149 public:
150  constexpr QMutex() = default;
151  ~QMutex()
152  {
153  QMutexPrivate *d = d_ptr.loadRelaxed();
154  if (d)
155  destroyInternal(d);
156  }
157 
158 #ifdef Q_QDOC
159  inline void lock() QT_MUTEX_LOCK_NOEXCEPT;
160  inline void unlock() noexcept;
161  bool tryLock() noexcept;
162 #endif
163 
164  // Lockable concept
165  bool try_lock() noexcept { return tryLock(); }
166 
167 
168  using QBasicMutex::tryLock;
169  bool tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT
170  {
171  if (fastTryLock())
172  return true;
173  return lockInternal(timeout);
174  }
175 
176  // TimedLockable concept
177  template <class Rep, class Period>
178  bool try_lock_for(std::chrono::duration<Rep, Period> duration)
179  {
180  return tryLock(QtPrivate::convertToMilliseconds(duration));
181  }
182 
183  // TimedLockable concept
184  template<class Clock, class Duration>
185  bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint)
186  {
187  // Implemented in terms of try_lock_for to honor the similar
188  // requirement in N4606 § 30.4.1.3 [thread.timedmutex.requirements]/12.
189 
190  return try_lock_for(timePoint - Clock::now());
191  }
192 };
193 
194 class Q_CORE_EXPORT QRecursiveMutex
195 {
197  // written to by the thread that first owns 'mutex';
198  // read during attempts to acquire ownership of 'mutex' from any other thread:
199  QAtomicPointer<void> owner = nullptr;
200  // only ever accessed from the thread that owns 'mutex':
201  uint count = 0;
202  QMutex mutex;
203 
204 public:
205  constexpr QRecursiveMutex() = default;
206  ~QRecursiveMutex();
207 
208 
209  // BasicLockable concept
210  void lock() QT_MUTEX_LOCK_NOEXCEPT
211  { tryLock(-1); }
212  bool tryLock(int timeout = 0) QT_MUTEX_LOCK_NOEXCEPT;
213  // BasicLockable concept
214  void unlock() noexcept;
215 
216  // Lockable concept
217  bool try_lock() QT_MUTEX_LOCK_NOEXCEPT { return tryLock(); }
218 
219  // TimedLockable concept
220  template <class Rep, class Period>
221  bool try_lock_for(std::chrono::duration<Rep, Period> duration)
222  {
223  return tryLock(QtPrivate::convertToMilliseconds(duration));
224  }
225 
226  // TimedLockable concept
227  template<class Clock, class Duration>
228  bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint)
229  {
230  // Implemented in terms of try_lock_for to honor the similar
231  // requirement in N4606 § 30.4.1.3 [thread.timedmutex.requirements]/12.
232 
233  return try_lock_for(timePoint - Clock::now());
234  }
235 };
236 
237 template <typename Mutex>
238 class [[nodiscard]] QMutexLocker
239 {
240 public:
241  inline explicit QMutexLocker(Mutex *mutex) QT_MUTEX_LOCK_NOEXCEPT
242  {
243  m = mutex;
244  if (Q_LIKELY(mutex)) {
245  mutex->lock();
246  isLocked = true;
247  }
248  }
249  inline ~QMutexLocker() {
250  unlock();
251  }
252 
253  inline void unlock() noexcept
254  {
255  if (!isLocked)
256  return;
257  m->unlock();
258  isLocked = false;
259  }
260 
261  inline void relock() QT_MUTEX_LOCK_NOEXCEPT
262  {
263  if (isLocked)
264  return;
265  if (m) {
266  m->lock();
267  isLocked = true;
268  }
269  }
270 
271  Mutex *mutex() const
272  {
273  return m;
274  }
275 private:
277 
278  Mutex *m;
279  bool isLocked = false;
280 };
281 
282 #else // !QT_CONFIG(thread) && !Q_CLANG_QDOC
283 
284 class QMutex
285 {
286 public:
287 
288  constexpr QMutex() noexcept { }
289 
290  inline void lock() noexcept {}
291  inline bool tryLock(int timeout = 0) noexcept { Q_UNUSED(timeout); return true; }
292  inline bool try_lock() noexcept { return true; }
293  inline void unlock() noexcept {}
294 
295  template <class Rep, class Period>
296  inline bool try_lock_for(std::chrono::duration<Rep, Period> duration) noexcept
297  {
298  Q_UNUSED(duration);
299  return true;
300  }
301 
302  template<class Clock, class Duration>
303  inline bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint) noexcept
304  {
305  Q_UNUSED(timePoint);
306  return true;
307  }
308 
309 private:
311 };
312 
313 class QRecursiveMutex : public QMutex {};
314 
315 template <typename Mutex>
316 class [[nodiscard]] QMutexLocker
317 {
318 public:
319  inline explicit QMutexLocker(Mutex *) noexcept {}
320  inline ~QMutexLocker() noexcept {}
321 
322  inline void unlock() noexcept {}
323  void relock() noexcept {}
324  inline Mutex *mutex() const noexcept { return nullptr; }
325 
326 private:
328 };
329 
331 
332 #endif // !QT_CONFIG(thread) && !Q_CLANG_QDOC
333 
335 
336 #endif // QMUTEX_H
The QMutex class provides access serialization between threads.
Definition: qmutex.h:285
bool tryLock(int timeout=0) noexcept
Definition: qmutex.h:291
bool try_lock_for(std::chrono::duration< Rep, Period > duration) noexcept
Definition: qmutex.h:296
void unlock() noexcept
Definition: qmutex.h:293
constexpr QMutex() noexcept
Definition: qmutex.h:288
bool try_lock() noexcept
Definition: qmutex.h:292
bool try_lock_until(std::chrono::time_point< Clock, Duration > timePoint) noexcept
Definition: qmutex.h:303
void lock() noexcept
Definition: qmutex.h:290
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes.
Definition: qmutex.h:317
void unlock() noexcept
Definition: qmutex.h:322
QMutexLocker(Mutex *) noexcept
Definition: qmutex.h:319
~QMutexLocker() noexcept
Definition: qmutex.h:320
void relock() noexcept
Definition: qmutex.h:323
Mutex * mutex() const noexcept
Definition: qmutex.h:324
The QRecursiveMutex class provides access serialization between threads.
Definition: qmutex.h:313
auto it unsigned count const
Definition: hb-iter.hh:848
#define inline
Definition: md4c.c:45
std::chrono::milliseconds ms
#define Q_LIKELY(x)
#define Q_DISABLE_COPY_MOVE(Class)
Definition: qglobal.h:519
size_t quintptr
Definition: qglobal.h:310
unsigned int uint
Definition: qglobal.h:334
#define Q_DISABLE_COPY(Class)
Definition: qglobal.h:515
QMutex QBasicMutex
Definition: qmutex.h:330
const GLfloat * m
GLenum GLenum GLsizei count
GLbitfield GLuint64 timeout
[4]
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
Q_UNUSED(salary)
[21]
mutex tryLock(deadline.remainingTime())
[4]
QObject::connect nullptr
QReadWriteLock lock
[0]
mutex unlock()
QMutex mutex