Fix race condition in QThreadPool::clear
Since we drop the lock while deleting threads, we need to handle the queue possibly being accessed and changed by the pool threads while clear() is running. Pick-to: 5.15 Fixes: QTBUG-87092 Change-Id: I7611edab90520454278502a58621e299f9cd1f6e Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
This commit is contained in:
parent
4d943225eb
commit
fe36d47b37
@ -325,7 +325,8 @@ bool QThreadPoolPrivate::waitForDone(int msecs)
|
||||
void QThreadPoolPrivate::clear()
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
for (QueuePage *page : qAsConst(queue)) {
|
||||
while (!queue.isEmpty()) {
|
||||
auto *page = queue.takeLast();
|
||||
while (!page->isFinished()) {
|
||||
QRunnable *r = page->pop();
|
||||
if (r && r->autoDelete()) {
|
||||
@ -335,9 +336,8 @@ void QThreadPoolPrivate::clear()
|
||||
locker.relock();
|
||||
}
|
||||
}
|
||||
delete page;
|
||||
}
|
||||
qDeleteAll(queue);
|
||||
queue.clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -93,6 +93,7 @@ private slots:
|
||||
void priorityStart();
|
||||
void waitForDone();
|
||||
void clear();
|
||||
void clearWithAutoDelete();
|
||||
void tryTake();
|
||||
void waitForDoneTimeout();
|
||||
void destroyingWaitsForTasksToFinish();
|
||||
@ -974,6 +975,31 @@ void tst_QThreadPool::clear()
|
||||
QCOMPARE(count.loadRelaxed(), threadPool.maxThreadCount());
|
||||
}
|
||||
|
||||
void tst_QThreadPool::clearWithAutoDelete()
|
||||
{
|
||||
class MyRunnable : public QRunnable
|
||||
{
|
||||
public:
|
||||
MyRunnable() {}
|
||||
void run() override { QThread::usleep(30); }
|
||||
};
|
||||
|
||||
QThreadPool threadPool;
|
||||
threadPool.setMaxThreadCount(4);
|
||||
const int loopCount = 20;
|
||||
const int batchSize = 500;
|
||||
// Should not crash see QTBUG-87092
|
||||
for (int i = 0; i < loopCount; i++) {
|
||||
threadPool.clear();
|
||||
for (int j = 0; j < batchSize; j++) {
|
||||
auto *runnable = new MyRunnable();
|
||||
runnable->setAutoDelete(true);
|
||||
threadPool.start(runnable);
|
||||
}
|
||||
}
|
||||
QVERIFY(threadPool.waitForDone());
|
||||
}
|
||||
|
||||
void tst_QThreadPool::tryTake()
|
||||
{
|
||||
QSemaphore sem(0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user