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