~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/corelib/thread/qmutex.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the core module of the Qt Toolkit.
 
6
**
 
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.
 
10
**
 
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.
 
15
**
 
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.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
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.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "qplatformdefs.h"
 
30
#include "qmutex.h"
 
31
 
 
32
#ifndef QT_NO_THREAD
 
33
#include "qatomic.h"
 
34
#include "qmutex_p.h"
 
35
 
 
36
/*!
 
37
    \class QMutex
 
38
    \brief The QMutex class provides access serialization between threads.
 
39
 
 
40
    \threadsafe
 
41
 
 
42
    \ingroup thread
 
43
    \ingroup environment
 
44
    \mainclass
 
45
 
 
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
 
51
    consistently.
 
52
 
 
53
    For example, say there is a method that prints a message to the
 
54
    user on two lines:
 
55
 
 
56
    \code
 
57
        int number = 6;
 
58
 
 
59
        void method1()
 
60
        {
 
61
            number *= 5;
 
62
            number /= 4;
 
63
        }
 
64
 
 
65
        void method2()
 
66
        {
 
67
            number *= 3;
 
68
            number /= 2;
 
69
        }
 
70
    \endcode
 
71
 
 
72
    If these two methods are called in succession, the following happens:
 
73
 
 
74
    \code
 
75
        // method1()
 
76
        number *= 5;        // number is now 30
 
77
        number /= 4;        // number is now 7
 
78
 
 
79
        // method2()
 
80
        number *= 3;        // nubmer is now 21
 
81
        number /= 2;        // number is now 10
 
82
    \endcode
 
83
 
 
84
    If these two methods are called simultaneously from two threads then the
 
85
    following sequence could result:
 
86
 
 
87
    \code
 
88
        // Thread 1 calls method1()
 
89
        number *= 5;        // number is now 30
 
90
 
 
91
        // Thread 2 calls method2().
 
92
        //
 
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
 
97
 
 
98
        // Thread 1 finishes executing.
 
99
        number /= 4;        // number is now 11, instead of 10
 
100
    \endcode
 
101
 
 
102
    If we add a mutex, we should get the result we want:
 
103
 
 
104
    \code
 
105
        QMutex mutex;
 
106
        int number = 6;
 
107
 
 
108
        void method1()
 
109
        {
 
110
            mutex.lock();
 
111
            number *= 5;
 
112
            number /= 4;
 
113
            mutex.unlock();
 
114
        }
 
115
 
 
116
        void method2()
 
117
        {
 
118
            mutex.lock();
 
119
            number *= 3;
 
120
            number /= 2;
 
121
            mutex.unlock();
 
122
        }
 
123
    \endcode
 
124
 
 
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
 
128
    particular sequence.
 
129
 
 
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
 
133
    tryLock().
 
134
 
 
135
    \sa QMutexLocker, QReadWriteLock, QSemaphore, QWaitCondition
 
136
*/
 
137
 
 
138
/*!
 
139
    \enum QMutex::RecursionMode
 
140
 
 
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
 
144
                      have been made.
 
145
 
 
146
    \value NonRecursive  In this mode, a thread may only lock a mutex
 
147
                         once.
 
148
 
 
149
    \sa QMutex()
 
150
*/
 
151
 
 
152
/*!
 
153
    Constructs a new mutex. The mutex is created in an unlocked state.
 
154
 
 
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.
 
159
 
 
160
    \sa lock(), unlock()
 
161
*/
 
162
QMutex::QMutex(RecursionMode mode)
 
163
    : d(new QMutexPrivate(mode))
 
164
{ }
 
165
 
 
166
/*!
 
167
    Destroys the mutex.
 
168
 
 
169
    \warning Destroying a locked mutex may result in undefined behavior.
 
170
*/
 
171
QMutex::~QMutex()
 
172
{ delete d; }
 
173
 
 
174
/*!
 
175
    Locks the mutex. If another thread has locked the mutex then this
 
176
    call will block until that thread has unlocked it.
 
177
 
 
178
    \sa unlock()
 
179
*/
 
180
void QMutex::lock()
 
181
{
 
182
    ulong self = d->self();
 
183
 
 
184
    int sentinel;
 
185
    forever {
 
186
        sentinel = d->lock;
 
187
        if (d->lock.testAndSet(sentinel, sentinel + 1))
 
188
            break;
 
189
    }
 
190
    if (sentinel != 0) {
 
191
        if (!d->recursive || d->owner != self) {
 
192
            if (d->owner == self) {
 
193
                qWarning("QMutex::lock(): Deadlock detected in thread %ld", d->owner);
 
194
            }
 
195
 
 
196
            // didn't get the lock, wait for it
 
197
            d->wait();
 
198
        }
 
199
 
 
200
        // don't need to wait for the lock anymore
 
201
        d->lock.deref();
 
202
    }
 
203
    d->owner = self;
 
204
    ++d->count;
 
205
    Q_ASSERT_X(d->count != 0, "QMutex::lock()", "Overflow in recursion counter");
 
206
}
 
207
 
 
208
/*!
 
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.
 
212
 
 
213
    If the lock was obtained, the mutex must be unlocked with unlock()
 
214
    before another thread can successfully lock it.
 
215
 
 
216
    \sa lock(), unlock()
 
217
*/
 
218
bool QMutex::tryLock()
 
219
{
 
220
    ulong self = d->self();
 
221
 
 
222
    int sentinel;
 
223
    forever {
 
224
        sentinel = d->lock;
 
225
        if (d->lock.testAndSet(sentinel, sentinel + 1))
 
226
            break;
 
227
    }
 
228
    if (sentinel != 0) {
 
229
        // we're not going to wait for lock
 
230
        d->lock.deref();
 
231
 
 
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
 
235
            return false;
 
236
        }
 
237
    }
 
238
    d->owner = self;
 
239
    ++d->count;
 
240
    return true;
 
241
}
 
242
 
 
243
/*!
 
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.
 
247
 
 
248
    \sa lock()
 
249
*/
 
250
void QMutex::unlock()
 
251
{
 
252
    Q_ASSERT_X(d->owner == d->self(), "QMutex::unlock()",
 
253
               "A mutex must be unlocked in the same thread that locked it.");
 
254
 
 
255
    if (!--d->count) {
 
256
        d->owner = 0;
 
257
        if (!d->lock.testAndSet(1, 0))
 
258
            d->wakeUp();
 
259
    }
 
260
}
 
261
 
 
262
/*!
 
263
    \fn bool QMutex::locked()
 
264
 
 
265
    Returns true if the mutex is locked by another thread; otherwise
 
266
    returns false.
 
267
 
 
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()
 
270
    instead.
 
271
 
 
272
    \oldcode
 
273
        bool isLocked = mutex.locked();
 
274
    \newcode
 
275
        bool isLocked = true;
 
276
        if (mutex.tryLock()) {
 
277
            mutex.unlock();
 
278
            isLocked = false;
 
279
        }
 
280
    \endcode
 
281
*/
 
282
 
 
283
/*!
 
284
    \class QMutexLocker
 
285
    \brief The QMutexLocker class is a convenience class that simplifies
 
286
    locking and unlocking mutexes.
 
287
 
 
288
    \threadsafe
 
289
 
 
290
    \ingroup thread
 
291
    \ingroup environment
 
292
 
 
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.
 
298
 
 
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.
 
302
 
 
303
    For example, this complex function locks a QMutex upon entering
 
304
    the function and unlocks the mutex at all the exit points:
 
305
 
 
306
    \code
 
307
        int complexFunction(int flag)
 
308
        {
 
309
            mutex.lock();
 
310
 
 
311
            int retVal = 0;
 
312
 
 
313
            switch (flag) {
 
314
            case 0:
 
315
            case 1:
 
316
                mutex.unlock();
 
317
                return moreComplexFunction(flag);
 
318
            case 2:
 
319
                {
 
320
                    int status = anotherFunction();
 
321
                    if (status < 0) {
 
322
                        mutex.unlock();
 
323
                        return -2;
 
324
                    }
 
325
                    retVal = status + flag;
 
326
                }
 
327
                break;
 
328
            default:
 
329
                if (flag > 10) {
 
330
                    mutex.unlock();
 
331
                    return -1;
 
332
                }
 
333
                break;
 
334
            }
 
335
 
 
336
            mutex.unlock();
 
337
            return retVal;
 
338
        }
 
339
    \endcode
 
340
 
 
341
    This example function will get more complicated as it is
 
342
    developed, which increases the likelihood that errors will occur.
 
343
 
 
344
    Using QMutexLocker greatly simplifies the code, and makes it more
 
345
    readable:
 
346
 
 
347
    \code
 
348
        int complexFunction(int flag)
 
349
        {
 
350
            QMutexLocker locker(&mutex);
 
351
 
 
352
            int retVal = 0;
 
353
 
 
354
            switch (flag) {
 
355
            case 0:
 
356
            case 1:
 
357
                return moreComplexFunction(flag);
 
358
            case 2:
 
359
                {
 
360
                    int status = anotherFunction();
 
361
                    if (status < 0)
 
362
                        return -2;
 
363
                    retVal = status + flag;
 
364
                }
 
365
                break;
 
366
            default:
 
367
                if (flag > 10)
 
368
                    return -1;
 
369
                break;
 
370
            }
 
371
 
 
372
            return retVal;
 
373
        }
 
374
    \endcode
 
375
 
 
376
    Now, the mutex will always be unlocked when the QMutexLocker
 
377
    object is destroyed (when the function returns since \c locker is
 
378
    an auto variable).
 
379
 
 
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.
 
384
 
 
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:
 
389
 
 
390
    \code
 
391
        class SignalWaiter
 
392
        {
 
393
        private:
 
394
            QMutexLocker locker;
 
395
 
 
396
        public:
 
397
            SignalWaiter(QMutex *mutex)
 
398
                : locker(mutex)
 
399
            {
 
400
            }
 
401
 
 
402
            void waitForSignal()
 
403
            {
 
404
                ...
 
405
                while (!signalled)
 
406
                    waitCondition.wait(locker.mutex());
 
407
                ...
 
408
            }
 
409
        };
 
410
    \endcode
 
411
 
 
412
    \sa QReadLocker, QWriteLocker, QMutex
 
413
*/
 
414
 
 
415
/*!
 
416
    \fn QMutexLocker::QMutexLocker(QMutex *mutex)
 
417
 
 
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.
 
421
 
 
422
    \sa QMutex::lock()
 
423
*/
 
424
 
 
425
/*!
 
426
    \fn QMutexLocker::~QMutexLocker()
 
427
 
 
428
    Destroys the QMutexLocker and unlocks the mutex that was locked
 
429
    in the constructor.
 
430
 
 
431
    \sa QMutex::unlock()
 
432
*/
 
433
 
 
434
/*!
 
435
    \fn QMutex *QMutexLocker::mutex() const
 
436
 
 
437
    Returns a pointer to the mutex that was locked in the
 
438
    constructor.
 
439
*/
 
440
 
 
441
/*!
 
442
    \fn void QMutexLocker::unlock()
 
443
 
 
444
    Unlocks this mutex locker.
 
445
 
 
446
    \sa relock()
 
447
*/
 
448
 
 
449
/*!
 
450
    \fn void QMutexLocker::relock()
 
451
 
 
452
    Relocks an unlocked mutex locker.
 
453
 
 
454
    \sa unlock()
 
455
*/
 
456
 
 
457
/*!
 
458
    \fn QMutex::QMutex(bool recursive)
 
459
 
 
460
    Use the constructor that takes a RecursionMode parameter instead.
 
461
*/
 
462
 
 
463
#endif // QT_NO_THREAD