-
-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
QCoroThread: implement wrapper for QThread
A coroutine-friendly wrapper to co_await a thread to start or finish.
- Loading branch information
Showing
8 changed files
with
244 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#include <QCoroThread> | ||
#include <QThread> | ||
|
||
#include <memory> | ||
|
||
QCoro::Task<void> MainWindow::processData(const QVector<qint64> &data) { | ||
std::unique_ptr<QThread> thread(QThread::create([data]() { | ||
// Perform some intesive calculation | ||
})); | ||
thread->start(); | ||
|
||
ui->setState(tr("Processing is starting...")); | ||
co_await qCoro(thread.get()).waitForStarted(); | ||
ui->setState(tr("Processing data...")); | ||
co_await qCoro(thread.get()).waitForFinished(); | ||
ui->setState(tr("Processing done.")); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
<!-- | ||
SPDX-FileCopyrightText: 2022 Daniel Vrátil <dvratil@kde.org> | ||
SPDX-License-Identifier: GFDL-1.3-or-later | ||
--> | ||
|
||
# QThread | ||
|
||
{{ doctable("Core", "QCoroThread", ("core/qthread", "QCoroThread")) }} | ||
|
||
[`QThread`][qtdoc-qthread] has two events: `started` and `finished`. QCoro provides | ||
a coroutine-friendly wrapper for `QThread` - `QCoroThread`, which allows `co_await`ing | ||
those events. | ||
|
||
To wrap a `QThread` object into the `QCoroThread` wrapper, use [`qCoro()`][qcoro-coro]: | ||
|
||
```cpp | ||
QCoroThread qCoro(QThread &); | ||
QCoroThread qCoro(QThread *); | ||
``` | ||
## `waitForStarted()` | ||
Waits for the thread to start. Returns `true` if the thread is already running | ||
or when the thread starts within the specified timeout. If the thread has already | ||
finished or fails to start within the specified timeout, the coroutine will return | ||
`false`. | ||
If the timeout is set to -1, the operation will never time out. | ||
See documentation for [`QThread::started()`][qtdoc-qthread-started] for details. | ||
```cpp | ||
QCoro::Task<bool> QCoroThread::waitForStarted(std::chrono::milliseconds timeout); | ||
``` | ||
|
||
## `waitForFinished()` | ||
|
||
Waits for the Waits for the process to finish or until it times out. Returns `bool` indicating | ||
whether the process has finished successfuly (`true`) or timed out (`false`). | ||
thread to finish. Returns `true` if the thread has already finished | ||
or if it finishes within the specified timeout. If the thread has not started yet | ||
or fails to stop within the specified timeout the coroutine will return `false`. | ||
|
||
If the timeout is set to -1, the operation will never time out. | ||
|
||
See documentation for [`QThread::finished()`][qtdoc-qthread-finished] for details. | ||
|
||
```cpp | ||
QCoro::Task<bool> QCoroThread::waitForFinished(std::chrono::milliseconds timeout); | ||
``` | ||
## Examples | ||
```cpp | ||
{% include "../../examples/qthread.cpp" %} | ||
``` | ||
|
||
|
||
[qtdoc-qthread]: https://doc.qt.io/qt-5/qthread.html | ||
[qtdoc-qthread-waitForStarted]: https://doc.qt.io/qt-5/qthread.html#waitForStarted | ||
[qtdoc-qthread-waitForFiished]: https://doc.qt.io/qt-5/qthread.html#waitForFinished | ||
[qcoro-coro]: ../coro/coro.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// SPDX-FileCopyrightText: 2022 Daniel Vrátil <dvratil@kde.org> | ||
// | ||
// SPDX-License-Identifier: MIT | ||
|
||
#include "qcorothread.h" | ||
#include "qcorosignal.h" | ||
|
||
#include <QThread> | ||
|
||
using namespace QCoro::detail; | ||
|
||
QCoroThread::QCoroThread(QThread *thread) | ||
: mThread(thread) | ||
{} | ||
|
||
QCoro::Task<bool> QCoroThread::waitForStarted(std::chrono::milliseconds timeout) { | ||
if (mThread->isRunning()) { | ||
co_return true; | ||
} | ||
if (mThread->isFinished()) { | ||
co_return false; | ||
} | ||
|
||
const auto result = co_await qCoro(mThread.data(), &QThread::started, timeout); | ||
co_return result.has_value(); | ||
} | ||
|
||
QCoro::Task<bool> QCoroThread::waitForFinished(std::chrono::milliseconds timeout) { | ||
if (mThread->isFinished()) { | ||
co_return true; | ||
} | ||
if (!mThread->isRunning()) { | ||
co_return false; | ||
} | ||
|
||
const auto result = co_await qCoro(mThread.data(), &QThread::finished, timeout); | ||
co_return result.has_value(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// SPDX-FileCopyrightText: 2022 Daniel Vrátil <dvratil@kde.org> | ||
// | ||
// SPDX-License-Identifier: MIT | ||
|
||
#pragma once | ||
|
||
#include <QPointer> | ||
|
||
class QThread; | ||
|
||
namespace QCoro { | ||
template<typename T> | ||
class Task; | ||
} // namespace QCoro | ||
|
||
namespace QCoro::detail { | ||
|
||
class QCoroThread { | ||
public: | ||
explicit QCoroThread(QThread *thread); | ||
|
||
/** | ||
* \brief Coroutine that waits for a thread to get started. | ||
* | ||
* \return Returns `true` when the thread is already running or when it starts within the | ||
* specified timeout. If the thread has already finished, or the operation times out, the | ||
* coroutine returns `false`. | ||
* | ||
* If the timeout is -1 the operation will never time out. | ||
* | ||
* See [`QThread::started()`][qtdoc-qthread-started] documentation for details. | ||
* | ||
* [qtdoc-qthread-started]: https://doc.qt.io/qt-5/qthread.html#started | ||
*/ | ||
Task<bool> waitForStarted(std::chrono::milliseconds timeout = std::chrono::milliseconds{-1}); | ||
|
||
/** | ||
* \brief Coroutine that waits for a thread to finish. | ||
* | ||
* \return Returns `true` when the thread has already finished or when it finishes within | ||
* specified timeout. If the thread is not running and hasn't finished yet, or when the | ||
* operation times out, the coroutine returns `false`. | ||
* | ||
* If the timeout is -1 the operation will never time out. | ||
* | ||
* See [`QThread::finished()`][qtdoc-qthread-finished] documentation for details. | ||
* | ||
* [qdoc-qthread-finished]: https://doc.qt.io/qt-5/qthread.html#finished | ||
*/ | ||
Task<bool> waitForFinished(std::chrono::milliseconds timeout = std::chrono::milliseconds{-1}); | ||
|
||
private: | ||
QPointer<QThread> mThread; | ||
}; | ||
|
||
} // namespace QCoro::detail | ||
|
||
inline auto qCoro(QThread *thread) { | ||
return QCoro::detail::QCoroThread(thread); | ||
} | ||
|
||
inline auto qCoro(QThread &thread) { | ||
return QCoro::detail::QCoroThread(&thread); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// SPDX-FileCopyrightText: 2022 Daniel Vrátil <dvratil@kde.org> | ||
// | ||
// SPDX-License-Identifier: MIT | ||
|
||
#include "testobject.h" | ||
|
||
#include "qcoro/core/qcorothread.h" | ||
#include "qcoro/core/qcorosignal.h" | ||
|
||
#include <QThread> | ||
#include <QScopeGuard> | ||
|
||
#include <thread> | ||
#include <memory> | ||
|
||
using namespace std::chrono_literals; | ||
|
||
class QCoroThreadTest : public QCoro::TestObject<QCoroThreadTest> { | ||
Q_OBJECT | ||
|
||
private: | ||
QCoro::Task<> testWaitForStarted_coro(QCoro::TestContext) { | ||
std::unique_ptr<QThread> thread(QThread::create([]() { | ||
std::this_thread::sleep_for(100ms); | ||
})); | ||
|
||
QScopeGuard guard([&]() { thread->wait(); }); | ||
|
||
QCORO_DELAY(thread->start()); | ||
|
||
const bool ok = co_await qCoro(thread.get()).waitForStarted(); | ||
QCORO_VERIFY(thread->isRunning()); | ||
QCORO_VERIFY(ok); | ||
} | ||
|
||
QCoro::Task<> testWaitForFinished_coro(QCoro::TestContext) { | ||
std::unique_ptr<QThread> thread(QThread::create([]() { | ||
std::this_thread::sleep_for(100ms); | ||
})); | ||
|
||
thread->start(); | ||
co_await qCoro(thread.get()).waitForStarted(); | ||
QCORO_VERIFY(thread->isRunning()); | ||
const bool ok = co_await qCoro(thread.get()).waitForFinished(); | ||
QCORO_VERIFY(thread->isFinished()); | ||
|
||
QCORO_VERIFY(ok); | ||
} | ||
|
||
private Q_SLOTS: | ||
addTest(WaitForStarted) | ||
addTest(WaitForFinished) | ||
}; | ||
|
||
|
||
QTEST_GUILESS_MAIN(QCoroThreadTest) | ||
|
||
#include "qcorothread.moc" |