source: trunk/src/corelib/thread/qmutex.cpp@ 877

Last change on this file since 877 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 15.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qplatformdefs.h"
43#include "qmutex.h"
44#include <qdebug.h>
45
46#ifndef QT_NO_THREAD
47#include "qatomic.h"
48#include "qthread.h"
49#include "qmutex_p.h"
50
51QT_BEGIN_NAMESPACE
52
53/*!
54 \class QMutex
55 \brief The QMutex class provides access serialization between threads.
56
57 \threadsafe
58
59 \ingroup thread
60
61 The purpose of a QMutex is to protect an object, data structure or
62 section of code so that only one thread can access it at a time
63 (this is similar to the Java \c synchronized keyword). It is
64 usually best to use a mutex with a QMutexLocker since this makes
65 it easy to ensure that locking and unlocking are performed
66 consistently.
67
68 For example, say there is a method that prints a message to the
69 user on two lines:
70
71 \snippet doc/src/snippets/code/src_corelib_thread_qmutex.cpp 0
72
73 If these two methods are called in succession, the following happens:
74
75 \snippet doc/src/snippets/code/src_corelib_thread_qmutex.cpp 1
76
77 If these two methods are called simultaneously from two threads then the
78 following sequence could result:
79
80 \snippet doc/src/snippets/code/src_corelib_thread_qmutex.cpp 2
81
82 If we add a mutex, we should get the result we want:
83
84 \snippet doc/src/snippets/code/src_corelib_thread_qmutex.cpp 3
85
86 Then only one thread can modify \c number at any given time and
87 the result is correct. This is a trivial example, of course, but
88 applies to any other case where things need to happen in a
89 particular sequence.
90
91 When you call lock() in a thread, other threads that try to call
92 lock() in the same place will block until the thread that got the
93 lock calls unlock(). A non-blocking alternative to lock() is
94 tryLock().
95
96 \sa QMutexLocker, QReadWriteLock, QSemaphore, QWaitCondition
97*/
98
99/*!
100 \enum QMutex::RecursionMode
101
102 \value Recursive In this mode, a thread can lock the same mutex
103 multiple times and the mutex won't be unlocked
104 until a corresponding number of unlock() calls
105 have been made.
106
107 \value NonRecursive In this mode, a thread may only lock a mutex
108 once.
109
110 \sa QMutex()
111*/
112
113/*!
114 Constructs a new mutex. The mutex is created in an unlocked state.
115
116 If \a mode is QMutex::Recursive, a thread can lock the same mutex
117 multiple times and the mutex won't be unlocked until a
118 corresponding number of unlock() calls have been made. The
119 default is QMutex::NonRecursive.
120
121 \sa lock(), unlock()
122*/
123QMutex::QMutex(RecursionMode mode)
124 : d(new QMutexPrivate(mode))
125{ }
126
127/*!
128 Destroys the mutex.
129
130 \warning Destroying a locked mutex may result in undefined behavior.
131*/
132QMutex::~QMutex()
133{ delete d; }
134
135/*!
136 Locks the mutex. If another thread has locked the mutex then this
137 call will block until that thread has unlocked it.
138
139 Calling this function multiple times on the same mutex from the
140 same thread is allowed if this mutex is a
141 \l{QMutex::Recursive}{recursive mutex}. If this mutex is a
142 \l{QMutex::NonRecursive}{non-recursive mutex}, this function will
143 \e dead-lock when the mutex is locked recursively.
144
145 \sa unlock()
146*/
147void QMutex::lock()
148{
149 Qt::HANDLE self;
150
151 if (d->recursive) {
152 self = QThread::currentThreadId();
153 if (d->owner == self) {
154 ++d->count;
155 Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflow in recursion counter");
156 return;
157 }
158
159 bool isLocked = d->contenders.fetchAndAddAcquire(1) == 0;
160 if (!isLocked) {
161#ifndef QT_NO_DEBUG
162 if (d->owner == self)
163 qWarning() << "QMutex::lock: Deadlock detected in thread" << d->owner;
164#endif
165
166 // didn't get the lock, wait for it
167 isLocked = d->wait();
168 Q_ASSERT_X(isLocked, "QMutex::lock",
169 "Internal error, infinite wait has timed out.");
170
171 // don't need to wait for the lock anymore
172 d->contenders.deref();
173 }
174
175 d->owner = self;
176 ++d->count;
177 Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflow in recursion counter");
178 return;
179 }
180
181#ifndef QT_NO_DEBUG
182 self = QThread::currentThreadId();
183#endif
184
185 bool isLocked = d->contenders == 0 && d->contenders.testAndSetAcquire(0, 1);
186 if (!isLocked) {
187 int spinCount = 0;
188 int lastSpinCount = d->lastSpinCount;
189
190 enum { AdditionalSpins = 20, SpinCountPenalizationDivisor = 4 };
191 const int maximumSpinCount = lastSpinCount + AdditionalSpins;
192
193 do {
194 if (spinCount++ > maximumSpinCount) {
195 // puts("spinning useless, sleeping");
196 isLocked = d->contenders.fetchAndAddAcquire(1) == 0;
197 if (!isLocked) {
198#ifndef QT_NO_DEBUG
199 if (d->owner == self)
200 qWarning() << "QMutex::lock: Deadlock detected in thread" << d->owner;
201#endif
202
203 // didn't get the lock, wait for it
204 isLocked = d->wait();
205 Q_ASSERT_X(isLocked, "QMutex::lock",
206 "Internal error, infinite wait has timed out.");
207
208 // don't need to wait for the lock anymore
209 d->contenders.deref();
210 }
211 // decrease the lastSpinCount since we didn't actually get the lock by spinning
212 spinCount = -d->lastSpinCount / SpinCountPenalizationDivisor;
213 break;
214 }
215
216 isLocked = d->contenders == 0 && d->contenders.testAndSetAcquire(0, 1);
217 } while (!isLocked);
218
219 // adjust the last spin lock count
220 lastSpinCount = d->lastSpinCount;
221 d->lastSpinCount = spinCount >= 0
222 ? qMax(lastSpinCount, spinCount)
223 : lastSpinCount + spinCount;
224 }
225
226#ifndef QT_NO_DEBUG
227 d->owner = self;
228#endif
229}
230
231/*!
232 Attempts to lock the mutex. If the lock was obtained, this function
233 returns true. If another thread has locked the mutex, this
234 function returns false immediately.
235
236 If the lock was obtained, the mutex must be unlocked with unlock()
237 before another thread can successfully lock it.
238
239 Calling this function multiple times on the same mutex from the
240 same thread is allowed if this mutex is a
241 \l{QMutex::Recursive}{recursive mutex}. If this mutex is a
242 \l{QMutex::NonRecursive}{non-recursive mutex}, this function will
243 \e always return false when attempting to lock the mutex
244 recursively.
245
246 \sa lock(), unlock()
247*/
248bool QMutex::tryLock()
249{
250 Qt::HANDLE self;
251
252 if (d->recursive) {
253 self = QThread::currentThreadId();
254 if (d->owner == self) {
255 ++d->count;
256 Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
257 return true;
258 }
259
260 bool isLocked = d->contenders == 0 && d->contenders.testAndSetAcquire(0, 1);
261 if (!isLocked) {
262 // some other thread has the mutex locked, or we tried to
263 // recursively lock an non-recursive mutex
264 return isLocked;
265 }
266
267 d->owner = self;
268 ++d->count;
269 Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
270 return isLocked;
271 }
272
273#ifndef QT_NO_DEBUG
274 self = QThread::currentThreadId();
275#endif
276 bool isLocked = d->contenders == 0 && d->contenders.testAndSetAcquire(0, 1);
277 if (!isLocked) {
278 // some other thread has the mutex locked, or we tried to
279 // recursively lock an non-recursive mutex
280 return isLocked;
281 }
282#ifndef QT_NO_DEBUG
283 d->owner = self;
284#endif
285 return isLocked;
286}
287
288/*! \overload
289
290 Attempts to lock the mutex. This function returns true if the lock
291 was obtained; otherwise it returns false. If another thread has
292 locked the mutex, this function will wait for at most \a timeout
293 milliseconds for the mutex to become available.
294
295 Note: Passing a negative number as the \a timeout is equivalent to
296 calling lock(), i.e. this function will wait forever until mutex
297 can be locked if \a timeout is negative.
298
299 If the lock was obtained, the mutex must be unlocked with unlock()
300 before another thread can successfully lock it.
301
302 Calling this function multiple times on the same mutex from the
303 same thread is allowed if this mutex is a
304 \l{QMutex::Recursive}{recursive mutex}. If this mutex is a
305 \l{QMutex::NonRecursive}{non-recursive mutex}, this function will
306 \e always return false when attempting to lock the mutex
307 recursively.
308
309 \sa lock(), unlock()
310*/
311bool QMutex::tryLock(int timeout)
312{
313 Qt::HANDLE self;
314
315 if (d->recursive) {
316 self = QThread::currentThreadId();
317 if (d->owner == self) {
318 ++d->count;
319 Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
320 return true;
321 }
322
323 bool isLocked = d->contenders.fetchAndAddAcquire(1) == 0;
324 if (!isLocked) {
325 // didn't get the lock, wait for it
326 isLocked = d->wait(timeout);
327
328 // don't need to wait for the lock anymore
329 d->contenders.deref();
330 if (!isLocked)
331 return false;
332 }
333
334 d->owner = self;
335 ++d->count;
336 Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
337 return true;
338 }
339
340#ifndef QT_NO_DEBUG
341 self = QThread::currentThreadId();
342#endif
343 bool isLocked = d->contenders.fetchAndAddAcquire(1) == 0;
344 if (!isLocked) {
345 // didn't get the lock, wait for it
346 isLocked = d->wait(timeout);
347
348 // don't need to wait for the lock anymore
349 d->contenders.deref();
350 if (!isLocked)
351 return false;
352 }
353#ifndef QT_NO_DEBUG
354 d->owner = self;
355#endif
356 return true;
357}
358
359
360/*!
361 Unlocks the mutex. Attempting to unlock a mutex in a different
362 thread to the one that locked it results in an error. Unlocking a
363 mutex that is not locked results in undefined behavior.
364
365 \sa lock()
366*/
367void QMutex::unlock()
368{
369 Q_ASSERT_X(d->owner == QThread::currentThreadId(), "QMutex::unlock()",
370 "A mutex must be unlocked in the same thread that locked it.");
371
372 if (d->recursive) {
373 if (!--d->count) {
374 d->owner = 0;
375 if (!d->contenders.testAndSetRelease(1, 0))
376 d->wakeUp();
377 }
378 } else {
379#ifndef QT_NO_DEBUG
380 d->owner = 0;
381#endif
382 if (!d->contenders.testAndSetRelease(1, 0))
383 d->wakeUp();
384 }
385}
386
387/*!
388 \fn bool QMutex::locked()
389
390 Returns true if the mutex is locked by another thread; otherwise
391 returns false.
392
393 It is generally a bad idea to use this function, because code
394 that uses it has a race condition. Use tryLock() and unlock()
395 instead.
396
397 \oldcode
398 bool isLocked = mutex.locked();
399 \newcode
400 bool isLocked = true;
401 if (mutex.tryLock()) {
402 mutex.unlock();
403 isLocked = false;
404 }
405 \endcode
406*/
407
408/*!
409 \class QMutexLocker
410 \brief The QMutexLocker class is a convenience class that simplifies
411 locking and unlocking mutexes.
412
413 \threadsafe
414
415 \ingroup thread
416
417 Locking and unlocking a QMutex in complex functions and
418 statements or in exception handling code is error-prone and
419 difficult to debug. QMutexLocker can be used in such situations
420 to ensure that the state of the mutex is always well-defined.
421
422 QMutexLocker should be created within a function where a
423 QMutex needs to be locked. The mutex is locked when QMutexLocker
424 is created. You can unlock and relock the mutex with \c unlock()
425 and \c relock(). If locked, the mutex will be unlocked when the
426 QMutexLocker is destroyed.
427
428 For example, this complex function locks a QMutex upon entering
429 the function and unlocks the mutex at all the exit points:
430
431 \snippet doc/src/snippets/code/src_corelib_thread_qmutex.cpp 4
432
433 This example function will get more complicated as it is
434 developed, which increases the likelihood that errors will occur.
435
436 Using QMutexLocker greatly simplifies the code, and makes it more
437 readable:
438
439 \snippet doc/src/snippets/code/src_corelib_thread_qmutex.cpp 5
440
441 Now, the mutex will always be unlocked when the QMutexLocker
442 object is destroyed (when the function returns since \c locker is
443 an auto variable).
444
445 The same principle applies to code that throws and catches
446 exceptions. An exception that is not caught in the function that
447 has locked the mutex has no way of unlocking the mutex before the
448 exception is passed up the stack to the calling function.
449
450 QMutexLocker also provides a \c mutex() member function that returns
451 the mutex on which the QMutexLocker is operating. This is useful
452 for code that needs access to the mutex, such as
453 QWaitCondition::wait(). For example:
454
455 \snippet doc/src/snippets/code/src_corelib_thread_qmutex.cpp 6
456
457 \sa QReadLocker, QWriteLocker, QMutex
458*/
459
460/*!
461 \fn QMutexLocker::QMutexLocker(QMutex *mutex)
462
463 Constructs a QMutexLocker and locks \a mutex. The mutex will be
464 unlocked when the QMutexLocker is destroyed. If \a mutex is zero,
465 QMutexLocker does nothing.
466
467 \sa QMutex::lock()
468*/
469
470/*!
471 \fn QMutexLocker::~QMutexLocker()
472
473 Destroys the QMutexLocker and unlocks the mutex that was locked
474 in the constructor.
475
476 \sa QMutex::unlock()
477*/
478
479/*!
480 \fn QMutex *QMutexLocker::mutex() const
481
482 Returns a pointer to the mutex that was locked in the
483 constructor.
484*/
485
486/*!
487 \fn void QMutexLocker::unlock()
488
489 Unlocks this mutex locker. You can use \c relock() to lock
490 it again. It does not need to be locked when destroyed.
491
492 \sa relock()
493*/
494
495/*!
496 \fn void QMutexLocker::relock()
497
498 Relocks an unlocked mutex locker.
499
500 \sa unlock()
501*/
502
503/*!
504 \fn QMutex::QMutex(bool recursive)
505
506 Use the constructor that takes a RecursionMode parameter instead.
507*/
508
509QT_END_NAMESPACE
510
511#endif // QT_NO_THREAD
Note: See TracBrowser for help on using the repository browser.