forked from qt-creator/qt-creator
Fix a possible crash in StringTable on shutdown
The issue is that when a GC() function is being executed in a separate thread, the main thread may delete the StringTable (on shutdown) in the same time. The destructor of StringTable didn't check in any way that the other thread is still executing GC() method. In order to fix it we employ runAsync method, returning the handle to the running task. We store the handle in futureSynchronizer, and in destructor of StringTablePrivate we safely wait for all futures to be finished. Fixes: QTCREATORBUG-25417 Change-Id: I0039d6041276c521c221e8dfc3894e84e47b82a2 Reviewed-by: Christian Stenger <christian.stenger@qt.io> Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -26,9 +26,11 @@
|
||||
#include "stringtable.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/runextensions.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QElapsedTimer>
|
||||
#include <QFutureSynchronizer>
|
||||
#include <QMutex>
|
||||
#include <QSet>
|
||||
#include <QThreadPool>
|
||||
@@ -48,18 +50,14 @@ class StringTablePrivate : public QObject
|
||||
{
|
||||
public:
|
||||
StringTablePrivate();
|
||||
~StringTablePrivate() override { m_futureSynchronizer.waitForFinished(); }
|
||||
|
||||
QString insert(const QString &string);
|
||||
void startGC() { QThreadPool::globalInstance()->start(&m_gcRunner); }
|
||||
void addFuture(const QFuture<void> &future);
|
||||
void startGC() { addFuture(Utils::runAsync(&StringTablePrivate::GC, this)); }
|
||||
void GC();
|
||||
|
||||
class GCRunner: public QRunnable {
|
||||
StringTablePrivate &m_stringTable;
|
||||
|
||||
public:
|
||||
explicit GCRunner(StringTablePrivate &stringTable): m_stringTable(stringTable) {}
|
||||
void run() override { m_stringTable.GC(); }
|
||||
} m_gcRunner;
|
||||
QFutureSynchronizer<void> m_futureSynchronizer;
|
||||
|
||||
mutable QMutex m_lock;
|
||||
QAtomicInt m_stopGCRequested{false};
|
||||
@@ -67,15 +65,26 @@ public:
|
||||
QTimer m_gcCountDown;
|
||||
};
|
||||
|
||||
void StringTablePrivate::addFuture(const QFuture<void> &future)
|
||||
{
|
||||
m_futureSynchronizer.addFuture(future);
|
||||
const QList<QFuture<void>> futures = m_futureSynchronizer.futures();
|
||||
const int maxFuturesCount = 10;
|
||||
if (futures.count() <= maxFuturesCount)
|
||||
return;
|
||||
m_futureSynchronizer.clearFutures();
|
||||
for (const auto &future : futures) {
|
||||
if (!future.isFinished())
|
||||
m_futureSynchronizer.addFuture(future);
|
||||
}
|
||||
}
|
||||
|
||||
static StringTablePrivate *m_instance = nullptr;
|
||||
|
||||
StringTablePrivate::StringTablePrivate()
|
||||
: m_gcRunner(*this)
|
||||
{
|
||||
m_strings.reserve(1000);
|
||||
|
||||
m_gcRunner.setAutoDelete(false);
|
||||
|
||||
m_gcCountDown.setObjectName(QLatin1String("StringTable::m_gcCountDown"));
|
||||
m_gcCountDown.setSingleShot(true);
|
||||
m_gcCountDown.setInterval(GCTimeOut);
|
||||
|
Reference in New Issue
Block a user