From 081c001deb75fa38385d3ff8cbbdb4f788529133 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 5 Mar 2018 19:53:37 -0800 Subject: QSemaphore: fix deadlock when the woken up thread wakes up another When the thread that got woken up by release() is supposed to release() to wake up another thread, we were deadlocking. This happened because we cleared the bit indicating that there was contention when the first release(). Instead of storing a single bit, we now store the number of threads waiting. Task-number: QTBUG-66875 Change-Id: I72f5230ad59948f784eafffd15193873502ecba4 Reviewed-by: Lars Knoll --- .../corelib/thread/qsemaphore/tst_qsemaphore.cpp | 69 ++++++++++++++++++++++ 1 file changed, 69 insertions(+) (limited to 'tests/auto/corelib/thread') diff --git a/tests/auto/corelib/thread/qsemaphore/tst_qsemaphore.cpp b/tests/auto/corelib/thread/qsemaphore/tst_qsemaphore.cpp index a67ecc2471..b7134d0454 100644 --- a/tests/auto/corelib/thread/qsemaphore/tst_qsemaphore.cpp +++ b/tests/auto/corelib/thread/qsemaphore/tst_qsemaphore.cpp @@ -37,6 +37,8 @@ class tst_QSemaphore : public QObject Q_OBJECT private slots: void acquire(); + void multiRelease(); + void multiAcquireRelease(); void tryAcquire(); void tryAcquireWithTimeout_data(); void tryAcquireWithTimeout(); @@ -149,6 +151,73 @@ void tst_QSemaphore::acquire() QCOMPARE(semaphore.available(), 0); } +void tst_QSemaphore::multiRelease() +{ + class Thread : public QThread + { + public: + QSemaphore &sem; + Thread(QSemaphore &sem) : sem(sem) {} + + void run() override + { + sem.acquire(); + } + }; + + QSemaphore sem; + QVector threads; + threads.resize(4); + + for (Thread *&t : threads) + t = new Thread(sem); + for (Thread *&t : threads) + t->start(); + + // wait for all threads to reach the sem.acquire() and then + // release them all + QTest::qSleep(1); + sem.release(threads.size()); + + for (Thread *&t : threads) + t->wait(); + qDeleteAll(threads); +} + +void tst_QSemaphore::multiAcquireRelease() +{ + class Thread : public QThread + { + public: + QSemaphore &sem; + Thread(QSemaphore &sem) : sem(sem) {} + + void run() override + { + sem.acquire(); + sem.release(); + } + }; + + QSemaphore sem; + QVector threads; + threads.resize(4); + + for (Thread *&t : threads) + t = new Thread(sem); + for (Thread *&t : threads) + t->start(); + + // wait for all threads to reach the sem.acquire() and then + // release them all + QTest::qSleep(1); + sem.release(); + + for (Thread *&t : threads) + t->wait(); + qDeleteAll(threads); +} + void tst_QSemaphore::tryAcquire() { QSemaphore semaphore; -- cgit v1.2.3