Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-30872

The new implementation of QMutex lock for high number of threads

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • Not Evaluated
    • 5.1.0
    • 5.0.0
    • Core: Threads
    • None
    • 529b648ece265f30784dadb96624e94b4ced5aba

    Description

      I observe that for many running threads QMutex can block execution even when it is in released state. This is critical problem for us as it can lock program as result. I found that problem is with implementation of lockInternal, unlockInternal, allocate in qmutex.cpp file. Here is the scenario we have:

      STEP 1:
      many threads, one of them is ready to release mutex,
      while at least two other trying to acquire it

      d->waiters is 0

      Thread 1 release mutex in unlockInternal:
      539: if (d->waiters.fetchAndAddRelease(-QMutexPrivate::BigNumber) == 0) {

      d->waiters is now -QMutexPrivate::BigNumber

      Thread 2 try to acquire mutex in lockInternal:
      464: old_waiters = d->waiters.load();
      465: if (old_waiters == -QMutexPrivate::BigNumber) {
      468: if (d_ptr.testAndSetAcquire(d, dummyLocked())) {

      It acquire 'about to release mutex' by changing d to dummyLocked

      Thread 1 continue release procedure:

      546: d->derefWaiters(0);

      d->waiters is now back to 0

      Thread 3 try to acquire mutex in lockInternal:

      482: while (!d->waiters.testAndSetRelaxed(old_waiters, old_waiters + 1));

      d->waiters is now 1

      Thread 2 continue its dummy lock:

      471: d->waiters.store(0);

      d->waiters is force to 0

      Thread 3 continue wait procedure
      but it realize that mutex was already unlocked so decrease back waiters

      484: if (d != d_ptr.loadAcquire()) {
      486: if (old_waiters != QMutexPrivate::BigNumber) {
      489: d->waiters.deref();

      d->waiters became negative value of -1

      Neither thread need internal data so it is released back to pool
      The waiters counter in released internal structure is still -1

      STEP 2:
      Next time when any QMutex need internal data it call QMutexPrivate::allocate
      This function does not reset data, it return structure with d->waiters set to -1.

      Thread that request it increase d->waiters by one (to zero) and wait.
      Other thread that own mutex finished and skip wakeUp because d->waiters is zero.

      The waiting thread is now in permanently locked state on released mutex.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            ogoffart Olivier Goffart (Woboq GmbH)
            michalf Michal Furmanczyk
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes