Optimize QPromise destructor
Unify cancel and finish in QPromise destructor in a single call. This saves us one extra mutex lock and atomic state change. Task-number: QTBUG-84977 Change-Id: Iac06302c39a2863008b27325fcf6792d4f58c8ae Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
22248a4e96
commit
ce59ccb334
@ -110,14 +110,36 @@ static inline int switch_from_to(QAtomicInt &a, int from, int to)
|
|||||||
|
|
||||||
void QFutureInterfaceBase::cancel()
|
void QFutureInterfaceBase::cancel()
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&d->m_mutex);
|
cancel(CancelMode::CancelOnly);
|
||||||
if (d->state.loadRelaxed() & Canceled)
|
}
|
||||||
return;
|
|
||||||
|
void QFutureInterfaceBase::cancel(QFutureInterfaceBase::CancelMode mode)
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&d->m_mutex);
|
||||||
|
|
||||||
|
const auto oldState = d->state.loadRelaxed();
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case CancelMode::CancelAndFinish:
|
||||||
|
if ((oldState & Finished) && (oldState & Canceled))
|
||||||
|
return;
|
||||||
|
switch_from_to(d->state, suspendingOrSuspended | Running, Canceled | Finished);
|
||||||
|
break;
|
||||||
|
case CancelMode::CancelOnly:
|
||||||
|
if (oldState & Canceled)
|
||||||
|
return;
|
||||||
|
switch_from_to(d->state, suspendingOrSuspended, Canceled);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
switch_from_to(d->state, suspendingOrSuspended, Canceled);
|
|
||||||
d->waitCondition.wakeAll();
|
d->waitCondition.wakeAll();
|
||||||
d->pausedWaitCondition.wakeAll();
|
d->pausedWaitCondition.wakeAll();
|
||||||
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Canceled));
|
|
||||||
|
if (!(oldState & Canceled))
|
||||||
|
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Canceled));
|
||||||
|
if (mode == CancelMode::CancelAndFinish && !(oldState & Finished))
|
||||||
|
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Finished));
|
||||||
|
|
||||||
d->isValid = false;
|
d->isValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +154,8 @@ public:
|
|||||||
int loadState() const;
|
int loadState() const;
|
||||||
|
|
||||||
void cancel();
|
void cancel();
|
||||||
|
void cancelAndFinish() { cancel(CancelMode::CancelAndFinish); }
|
||||||
|
|
||||||
void setSuspended(bool suspend);
|
void setSuspended(bool suspend);
|
||||||
void toggleSuspended();
|
void toggleSuspended();
|
||||||
void reportSuspended() const;
|
void reportSuspended() const;
|
||||||
@ -216,6 +218,9 @@ protected:
|
|||||||
bool launchAsync() const;
|
bool launchAsync() const;
|
||||||
|
|
||||||
bool isRunningOrPending() const;
|
bool isRunningOrPending() const;
|
||||||
|
|
||||||
|
enum class CancelMode { CancelOnly, CancelAndFinish };
|
||||||
|
void cancel(CancelMode mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void swap(QFutureInterfaceBase &lhs, QFutureInterfaceBase &rhs) noexcept
|
inline void swap(QFutureInterfaceBase &lhs, QFutureInterfaceBase &rhs) noexcept
|
||||||
|
@ -70,10 +70,8 @@ public:
|
|||||||
return;
|
return;
|
||||||
// Otherwise, if computation is not finished at this point, cancel
|
// Otherwise, if computation is not finished at this point, cancel
|
||||||
// potential waits
|
// potential waits
|
||||||
if (!(state & QFutureInterfaceBase::State::Finished)) {
|
if (!(state & QFutureInterfaceBase::State::Finished))
|
||||||
d.cancel();
|
d.cancelAndFinish(); // cancel and finalize the state
|
||||||
finish(); // required to finalize the state
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Core QPromise APIs
|
// Core QPromise APIs
|
||||||
|
@ -107,6 +107,7 @@ private slots:
|
|||||||
void futureInterface();
|
void futureInterface();
|
||||||
void refcounting();
|
void refcounting();
|
||||||
void cancel();
|
void cancel();
|
||||||
|
void cancelAndFinish();
|
||||||
void statePropagation();
|
void statePropagation();
|
||||||
void multipleResults();
|
void multipleResults();
|
||||||
void indexedResults();
|
void indexedResults();
|
||||||
@ -865,6 +866,39 @@ void tst_QFuture::cancel()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QFuture::cancelAndFinish()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
QFutureInterface<void> fi;
|
||||||
|
|
||||||
|
fi.reportStarted();
|
||||||
|
fi.cancelAndFinish();
|
||||||
|
|
||||||
|
QVERIFY(fi.isStarted());
|
||||||
|
QVERIFY(!fi.isRunning());
|
||||||
|
QVERIFY(!fi.isSuspended());
|
||||||
|
QVERIFY(!fi.isSuspending());
|
||||||
|
QVERIFY(fi.isCanceled());
|
||||||
|
QVERIFY(fi.isFinished());
|
||||||
|
}
|
||||||
|
|
||||||
|
// The same with suspended state
|
||||||
|
{
|
||||||
|
QFutureInterface<void> fi;
|
||||||
|
|
||||||
|
fi.reportStarted();
|
||||||
|
fi.setSuspended(true);
|
||||||
|
fi.cancelAndFinish();
|
||||||
|
|
||||||
|
QVERIFY(fi.isStarted());
|
||||||
|
QVERIFY(!fi.isRunning());
|
||||||
|
QVERIFY(!fi.isSuspended());
|
||||||
|
QVERIFY(!fi.isSuspending());
|
||||||
|
QVERIFY(fi.isCanceled());
|
||||||
|
QVERIFY(fi.isFinished());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QFuture::statePropagation()
|
void tst_QFuture::statePropagation()
|
||||||
{
|
{
|
||||||
QFuture<void> f1;
|
QFuture<void> f1;
|
||||||
|
@ -46,6 +46,8 @@ private slots:
|
|||||||
void startFinish();
|
void startFinish();
|
||||||
void progressValueChanged();
|
void progressValueChanged();
|
||||||
void canceled();
|
void canceled();
|
||||||
|
void cancelAndFinish_data();
|
||||||
|
void cancelAndFinish();
|
||||||
void resultAt();
|
void resultAt();
|
||||||
void resultReadyAt();
|
void resultReadyAt();
|
||||||
void futureSignals();
|
void futureSignals();
|
||||||
@ -229,6 +231,42 @@ void tst_QFutureWatcher::canceled()
|
|||||||
future.waitForFinished();
|
future.waitForFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QFutureWatcher::cancelAndFinish_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<bool>("isCanceled");
|
||||||
|
QTest::addColumn<bool>("isFinished");
|
||||||
|
|
||||||
|
QTest::addRow("running") << false << false;
|
||||||
|
QTest::addRow("canceled") << true << false;
|
||||||
|
QTest::addRow("finished") << false << true;
|
||||||
|
QTest::addRow("canceledAndFinished") << true << true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QFutureWatcher::cancelAndFinish()
|
||||||
|
{
|
||||||
|
QFETCH(bool, isCanceled);
|
||||||
|
QFETCH(bool, isFinished);
|
||||||
|
|
||||||
|
QFutureInterface<void> fi;
|
||||||
|
QFutureWatcher<void> futureWatcher;
|
||||||
|
QSignalSpy finishedSpy(&futureWatcher, &QFutureWatcher<void>::finished);
|
||||||
|
QSignalSpy canceledSpy(&futureWatcher, &QFutureWatcher<void>::canceled);
|
||||||
|
futureWatcher.setFuture(fi.future());
|
||||||
|
|
||||||
|
fi.reportStarted();
|
||||||
|
|
||||||
|
if (isCanceled)
|
||||||
|
fi.cancel();
|
||||||
|
if (isFinished)
|
||||||
|
fi.reportFinished();
|
||||||
|
|
||||||
|
fi.cancelAndFinish();
|
||||||
|
|
||||||
|
// The signals should be emitted only once
|
||||||
|
QTRY_COMPARE(canceledSpy.count(), 1);
|
||||||
|
QTRY_COMPARE(finishedSpy.count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
class IntTask : public RunFunctionTaskBase<int>
|
class IntTask : public RunFunctionTaskBase<int>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user