ClassView: Stop the running timer in Parser thread on close

When we are going to delete Parser object, it may happen,
that its timer is still being active. A call to
parserThread.quit() won't stop the timer. When we quit the
thread and wait for it to finish, the thread's timer may
still be active. Then we delete the Parser in the main thread,
what cause the following warning to appear:
"QObject::killTimer: Timers cannot be stopped from another thread".
In order to fix it, we post a request to the parser's thread
for stopping the timer by a call to aboutToShutdown() with
Qt::BlockingQueuedConnection, just before quitting the thread,
as the thread's event loop should still be spinning and is
able to receive and handle our request. It's the only safe way
to stop the active timer that was started in another thread
- it must be stopped it the same thread it was started in.
Inside the call to aboutToShutdown() we mark that we don't want
to start the timer anymore with m_shuttingDown flag and we stop
the timer. After the blocking call returns to the main thread
we are sure that the timer is not active anymore and it won't
became active in the future, so we safely quit the thread and
delete the timer.

Task-number: QTCREATORBUG-25317
Change-Id: I3b95c062b5561588c45c223d8588b2b700ad4040
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Jarek Kobus
2021-02-16 02:26:21 +01:00
parent 4a15f6d16b
commit f200466066
3 changed files with 10 additions and 2 deletions

View File

@@ -123,6 +123,7 @@ Manager::Manager(QObject *parent)
Manager::~Manager() Manager::~Manager()
{ {
QMetaObject::invokeMethod(&d->parser, &Parser::aboutToShutdown, Qt::BlockingQueuedConnection);
d->parserThread.quit(); d->parserThread.quit();
d->parserThread.wait(); d->parserThread.wait();
delete d; delete d;

View File

@@ -89,6 +89,7 @@ public:
CPlusPlus::Document::Ptr document(const QString &fileName) const; CPlusPlus::Document::Ptr document(const QString &fileName) const;
QTimer timer; QTimer timer;
bool m_shuttingDown = false;
struct DocumentCache { struct DocumentCache {
unsigned treeRevision = 0; unsigned treeRevision = 0;
@@ -199,6 +200,12 @@ void Parser::setFlatMode(bool flatMode)
requestCurrentState(); requestCurrentState();
} }
void Parser::aboutToShutdown()
{
d->m_shuttingDown = true;
d->timer.stop();
}
/*! /*!
Returns the internal tree item for \a item. \a skipRoot skips the root Returns the internal tree item for \a item. \a skipRoot skips the root
item. item.
@@ -405,9 +412,8 @@ void Parser::parseDocument(const CPlusPlus::Document::Ptr &doc)
getParseDocumentTree(doc); getParseDocumentTree(doc);
if (!d->timer.isActive()) if (!d->timer.isActive() && !d->m_shuttingDown)
d->timer.start(400); //! Delay in msecs before an update d->timer.start(400); //! Delay in msecs before an update
return;
} }
/*! /*!

View File

@@ -62,6 +62,7 @@ public:
void resetDataToCurrentState(); void resetDataToCurrentState();
void parseDocument(const CPlusPlus::Document::Ptr &doc); void parseDocument(const CPlusPlus::Document::Ptr &doc);
void setFlatMode(bool flat); void setFlatMode(bool flat);
void aboutToShutdown();
signals: signals:
void treeDataUpdate(QSharedPointer<QStandardItem> result); void treeDataUpdate(QSharedPointer<QStandardItem> result);