mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2024-11-22 02:34:30 +08:00
Fix dispatching when app (or thread) terminated
Make sure to **not** notify handlers if the captured thread doesn't exist anymore, which would potentially result in dispatching to the wrong thread (ie. nullptr == current thread). This also applies when the app is shutting down and the even loop is not anymore available. In both cases, we should not trigger any error and skip notifications.
This commit is contained in:
parent
f794916be6
commit
313d3882d7
@ -32,7 +32,7 @@ namespace QtPromisePrivate {
|
|||||||
|
|
||||||
// https://stackoverflow.com/a/21653558
|
// https://stackoverflow.com/a/21653558
|
||||||
template <typename F>
|
template <typename F>
|
||||||
static void qtpromise_defer(F&& f, QThread* thread = nullptr)
|
static void qtpromise_defer(F&& f, const QPointer<QThread>& thread)
|
||||||
{
|
{
|
||||||
struct Event : public QEvent
|
struct Event : public QEvent
|
||||||
{
|
{
|
||||||
@ -43,11 +43,34 @@ static void qtpromise_defer(F&& f, QThread* thread = nullptr)
|
|||||||
FType m_f;
|
FType m_f;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!thread || thread->isFinished()) {
|
||||||
|
// Make sure to not call `f` if the captured thread doesn't exist anymore,
|
||||||
|
// which would potentially result in dispatching to the wrong thread (ie.
|
||||||
|
// nullptr == current thread). Since the target thread is gone, it should
|
||||||
|
// be safe to simply skip that notification.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QObject* target = QAbstractEventDispatcher::instance(thread);
|
QObject* target = QAbstractEventDispatcher::instance(thread);
|
||||||
|
if (!target && QCoreApplication::closingDown()) {
|
||||||
|
// When the app is shutting down, the even loop is not anymore available
|
||||||
|
// so we don't have any way to dispatch `f`. This case can happen when a
|
||||||
|
// promise is resolved after the app is requested to close, in which case
|
||||||
|
// we should not trigger any error and skip that notification.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Q_ASSERT_X(target, "postMetaCall", "Target thread must have an event loop");
|
Q_ASSERT_X(target, "postMetaCall", "Target thread must have an event loop");
|
||||||
QCoreApplication::postEvent(target, new Event(std::forward<F>(f)));
|
QCoreApplication::postEvent(target, new Event(std::forward<F>(f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
static void qtpromise_defer(F&& f)
|
||||||
|
{
|
||||||
|
Q_ASSERT(QThread::currentThread());
|
||||||
|
qtpromise_defer(std::forward<F>(f), QThread::currentThread());
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct PromiseDeduce
|
struct PromiseDeduce
|
||||||
{
|
{
|
||||||
|
@ -261,9 +261,9 @@ void tst_future::fail()
|
|||||||
QString result;
|
QString result;
|
||||||
auto input = QPromise<QString>::reject(MyException("bar"));
|
auto input = QPromise<QString>::reject(MyException("bar"));
|
||||||
auto output = input.fail([](const MyException& e) {
|
auto output = input.fail([](const MyException& e) {
|
||||||
return QtConcurrent::run([=]() {
|
return QtConcurrent::run([](const QString& error) {
|
||||||
return QString("foo%1").arg(e.error());
|
return QString("foo%1").arg(error);
|
||||||
});
|
}, e.error());
|
||||||
});
|
});
|
||||||
|
|
||||||
QCOMPARE(input.isRejected(), true);
|
QCOMPARE(input.isRejected(), true);
|
||||||
@ -282,9 +282,9 @@ void tst_future::fail_void()
|
|||||||
QString result;
|
QString result;
|
||||||
auto input = QPromise<void>::reject(MyException("bar"));
|
auto input = QPromise<void>::reject(MyException("bar"));
|
||||||
auto output = input.fail([&](const MyException& e) {
|
auto output = input.fail([&](const MyException& e) {
|
||||||
return QtConcurrent::run([&]() {
|
return QtConcurrent::run([&](const QString& error) {
|
||||||
result = e.error();
|
result = error;
|
||||||
});
|
}, e.error());
|
||||||
});
|
});
|
||||||
|
|
||||||
QCOMPARE(input.isRejected(), true);
|
QCOMPARE(input.isRejected(), true);
|
||||||
|
Loading…
Reference in New Issue
Block a user