1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the core module of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
29
#include "qplatformdefs.h"
38
\brief The QMutex class provides access serialization between threads.
46
The purpose of a QMutex is to protect an object, data structure or
47
section of code so that only one thread can access it at a time
48
(this is similar to the Java \c synchronized keyword). It is
49
usually best to use a mutex with a QMutexLocker since this makes
50
it easy to ensure that locking and unlocking are performed
53
For example, say there is a method that prints a message to the
72
If these two methods are called in succession, the following happens:
76
number *= 5; // number is now 30
77
number /= 4; // number is now 7
80
number *= 3; // nubmer is now 21
81
number /= 2; // number is now 10
84
If these two methods are called simultaneously from two threads then the
85
following sequence could result:
88
// Thread 1 calls method1()
89
number *= 5; // number is now 30
91
// Thread 2 calls method2().
93
// Most likely Thread 1 has been put to sleep by the operating
94
// system to allow Thread 2 to run.
95
number *= 3; // number is now 90
96
number /= 2; // number is now 45
98
// Thread 1 finishes executing.
99
number /= 4; // number is now 11, instead of 10
102
If we add a mutex, we should get the result we want:
125
Then only one thread can modify \c number at any given time and
126
the result is correct. This is a trivial example, of course, but
127
applies to any other case where things need to happen in a
130
When you call lock() in a thread, other threads that try to call
131
lock() in the same place will block until the thread that got the
132
lock calls unlock(). A non-blocking alternative to lock() is
135
\sa QMutexLocker, QReadWriteLock, QSemaphore, QWaitCondition
139
\enum QMutex::RecursionMode
141
\value Recursive In this mode, a thread can lock the same mutex
142
multiple times and the mutex won't be unlocked
143
until a corresponding number of unlock() calls
146
\value NonRecursive In this mode, a thread may only lock a mutex
153
Constructs a new mutex. The mutex is created in an unlocked state.
155
If \a mode is QMutex::Recursive, a thread can lock the same mutex
156
multiple times and the mutex won't be unlocked until a
157
corresponding number of unlock() calls have been made. The
158
default is QMutex::NonRecursive.
162
QMutex::QMutex(RecursionMode mode)
163
: d(new QMutexPrivate(mode))
169
\warning Destroying a locked mutex may result in undefined behavior.
175
Locks the mutex. If another thread has locked the mutex then this
176
call will block until that thread has unlocked it.
182
ulong self = d->self();
187
if (d->lock.testAndSet(sentinel, sentinel + 1))
191
if (!d->recursive || d->owner != self) {
192
if (d->owner == self) {
193
qWarning("QMutex::lock(): Deadlock detected in thread %ld", d->owner);
196
// didn't get the lock, wait for it
200
// don't need to wait for the lock anymore
205
Q_ASSERT_X(d->count != 0, "QMutex::lock()", "Overflow in recursion counter");
209
Attempts to lock the mutex. If the lock was obtained, this function
210
returns true. If another thread has locked the mutex, this
211
function returns false immediately.
213
If the lock was obtained, the mutex must be unlocked with unlock()
214
before another thread can successfully lock it.
218
bool QMutex::tryLock()
220
ulong self = d->self();
225
if (d->lock.testAndSet(sentinel, sentinel + 1))
229
// we're not going to wait for lock
232
if (!d->recursive || d->owner != self) {
233
// some other thread has the mutex locked, or we tried to
234
// recursively lock an non-recursive mutex
244
Unlocks the mutex. Attempting to unlock a mutex in a different
245
thread to the one that locked it results in an error. Unlocking a
246
mutex that is not locked results in undefined behavior.
250
void QMutex::unlock()
252
Q_ASSERT_X(d->owner == d->self(), "QMutex::unlock()",
253
"A mutex must be unlocked in the same thread that locked it.");
257
if (!d->lock.testAndSet(1, 0))
263
\fn bool QMutex::locked()
265
Returns true if the mutex is locked by another thread; otherwise
268
It is generally a bad idea to use this function, because code
269
that uses it has a race condition. Use tryLock() and unlock()
273
bool isLocked = mutex.locked();
275
bool isLocked = true;
276
if (mutex.tryLock()) {
285
\brief The QMutexLocker class is a convenience class that simplifies
286
locking and unlocking mutexes.
293
The purpose of QMutexLocker is to simplify QMutex locking and
294
unlocking. Locking and unlocking a QMutex in complex functions and
295
statements or in exception handling code is error-prone and
296
difficult to debug. QMutexLocker can be used in such situations
297
to ensure that the state of the mutex is always well-defined.
299
QMutexLocker should be created within a function where a QMutex
300
needs to be locked. The mutex is locked when QMutexLocker is
301
created, and unlocked when QMutexLocker is destroyed.
303
For example, this complex function locks a QMutex upon entering
304
the function and unlocks the mutex at all the exit points:
307
int complexFunction(int flag)
317
return moreComplexFunction(flag);
320
int status = anotherFunction();
325
retVal = status + flag;
341
This example function will get more complicated as it is
342
developed, which increases the likelihood that errors will occur.
344
Using QMutexLocker greatly simplifies the code, and makes it more
348
int complexFunction(int flag)
350
QMutexLocker locker(&mutex);
357
return moreComplexFunction(flag);
360
int status = anotherFunction();
363
retVal = status + flag;
376
Now, the mutex will always be unlocked when the QMutexLocker
377
object is destroyed (when the function returns since \c locker is
380
The same principle applies to code that throws and catches
381
exceptions. An exception that is not caught in the function that
382
has locked the mutex has no way of unlocking the mutex before the
383
exception is passed up the stack to the calling function.
385
QMutexLocker also provides a mutex() member function that returns
386
the mutex on which the QMutexLocker is operating. This is useful
387
for code that needs access to the mutex, such as
388
QWaitCondition::wait(). For example:
397
SignalWaiter(QMutex *mutex)
406
waitCondition.wait(locker.mutex());
412
\sa QReadLocker, QWriteLocker, QMutex
416
\fn QMutexLocker::QMutexLocker(QMutex *mutex)
418
Constructs a QMutexLocker and locks \a mutex. The mutex will be
419
unlocked when the QMutexLocker is destroyed. If \a mutex is zero,
420
QMutexLocker does nothing.
426
\fn QMutexLocker::~QMutexLocker()
428
Destroys the QMutexLocker and unlocks the mutex that was locked
435
\fn QMutex *QMutexLocker::mutex() const
437
Returns a pointer to the mutex that was locked in the
442
\fn void QMutexLocker::unlock()
444
Unlocks this mutex locker.
450
\fn void QMutexLocker::relock()
452
Relocks an unlocked mutex locker.
458
\fn QMutex::QMutex(bool recursive)
460
Use the constructor that takes a RecursionMode parameter instead.
463
#endif // QT_NO_THREAD