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

Recursively read-locking a QReadWriteLock fails if other thread is waiting for write lock

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P1: Critical
    • 5.5.1
    • 5.5.0, 5.6
    • Core: Threads
    • None
    • 0aedca2f9756fa33420fb6b3f003f364424f9134

    Description

      Consider the following example:

      #include <QThread>
      #include <QReadWriteLock>
      #include <QDebug>
      
      #include <unistd.h>
      
      class RecursiveLock : public QReadWriteLock
      {
      public:
          RecursiveLock() : QReadWriteLock(QReadWriteLock::Recursive) {}
      };
      
      RecursiveLock lock;
      
      class ReadLockThread : public QThread
      {
          Q_OBJECT
      protected:
          void run()
          {
              QReadLocker lock1(&lock);
              qDebug() << "Read lock 1";
              sleep(5);
              {
                  QReadLocker lock2(&lock);
                  qDebug() << "Read lock 2";
              }
          }
      };
      
      int main(int argc, char *argv[])
      {
          ReadLockThread t;
          t.start();
          sleep(2);
          QWriteLocker lock3(&lock);
          qDebug() << "Write lock";
      }
      
      #include "main.moc"
      

      This should (in most cases)
      1. start the thread
      2. acquire lock1
      3. start waiting on lock3 in the main thread
      4. acquire lock2 recursively
      5. stop the thread, releasing lock1 and lock2
      6. acquire lock3
      7. quit

      Actually it deadlocks at step 4, though. This seems to be a regression from 5.4 to 5.5.

      Backtraces of both threads during the deadlock:

      Thread 2 (Thread 0x7f8939d18700 (LWP 4630)):
      #0  pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
      No locals.
      #1  0x00007f893d9767fb in QWaitCondition::wait(QMutex*, unsigned long) () from /home/ulf/Qt/5.5/gcc_64/lib/libQt5Core.so.5
      No symbol table info available.
      #2  0x00007f893d96ec4c in QReadWriteLock::lockForRead() () from /home/ulf/Qt/5.5/gcc_64/lib/libQt5Core.so.5
      No symbol table info available.
      #3  0x00000000004018bb in QReadLocker::relock (this=0x7f8939d17e30) at ../../Qt/5.5/gcc_64/include/QtCore/qreadwritelock.h:98
      No locals.
      #4  0x0000000000401942 in QReadLocker::QReadLocker (this=0x7f8939d17e30, areadWriteLock=0x602ca8 <lock>) at ../../Qt/5.5/gcc_64/include/QtCore/qreadwritelock.h:117
      No locals.
      #5  0x0000000000401be5 in ReadLockThread::run (this=0x7ffc31e8f2e0) at ../deadlock/main.cpp:58
              lock2 = {q_val = 6302888}
              lock1 = {q_val = 6302889}
              __PRETTY_FUNCTION__ = "virtual void ReadLockThread::run()"
      #6  0x00007f893d9757df in ?? () from /home/ulf/Qt/5.5/gcc_64/lib/libQt5Core.so.5
      No symbol table info available.
      #7  0x00007f893d6bd0a4 in start_thread (arg=0x7f8939d18700) at pthread_create.c:309
              __res = <optimized out>
              pd = 0x7f8939d18700
              now = <optimized out>
              unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140227357280000, 7339065152721156614, 1, 140227429761120, 7, 140227357280000, -7292476246588098042, -7292486643519423994}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}}
              not_first_call = <optimized out>
              pagesize_m1 = <optimized out>
              sp = <optimized out>
              freesize = <optimized out>
              __PRETTY_FUNCTION__ = "start_thread"
      #8  0x00007f893cbd004d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
      No locals.
      
      Thread 1 (Thread 0x7f893e206740 (LWP 4622)):
      #0  pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
      No locals.
      #1  0x00007f893d9767fb in QWaitCondition::wait(QMutex*, unsigned long) () from /home/ulf/Qt/5.5/gcc_64/lib/libQt5Core.so.5
      No symbol table info available.
      #2  0x00007f893d96ee46 in QReadWriteLock::lockForWrite() () from /home/ulf/Qt/5.5/gcc_64/lib/libQt5Core.so.5
      No symbol table info available.
      #3  0x00000000004019eb in QWriteLocker::relock (this=0x7ffc31e8f2d0) at ../../Qt/5.5/gcc_64/include/QtCore/qreadwritelock.h:142
      No locals.
      #4  0x0000000000401a72 in QWriteLocker::QWriteLocker (this=0x7ffc31e8f2d0, areadWriteLock=0x602ca8 <lock>) at ../../Qt/5.5/gcc_64/include/QtCore/qreadwritelock.h:162
      No locals.
      #5  0x00000000004014c3 in main (argc=1, argv=0x7ffc31e8f418) at ../deadlock/main.cpp:69
              t = {<QThread> = {<No data fields>}, static staticMetaObject = {d = {superdata = 0x7f893e00e2c0 <QThread::staticMetaObject>, stringdata = 0x401fc0 <qt_meta_stringdata_ReadLockThread>, data = 0x402000 <qt_meta_data_ReadLockThread>, static_metacall = 0x401576 <ReadLockThread::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)>, relatedMetaObjects = 0x0, extradata = 0x0}}}
              lock3 = {q_val = 6302888}
              __PRETTY_FUNCTION__ = "int main(int, char**)"
      

      Attachments

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

        Activity

          People

            thiago Thiago Macieira
            ulherman Ulf Hermann
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes