Die QCoro-Bibliothek bietet eine Reihe von Tools zur Nutzung von C++20-Coroutinen mit Qt.
Schauen Sie sich das folgende Beispiel an, um zu sehen, was für eine erstaunliche Sache Coroutinen sind:
QNetworkAccessManager networkAccessManager;// co_await the Reply – die Coroutine wird angehalten, bis die QNetworkReply beendet ist.// Während die Coroutine angehalten ist, *läuft die Qt-Ereignisschleife wie gewohnt*.const QNetworkReply *reply = co_await networkAccessManager.get(url); // Sobald die Antwort fertig ist, wird Ihr Code hier fortgesetzt, als wäre gerade nichts Erstaunliches passiert ;-)const auto data = reply->readAll();
Es erfordert einen Compiler mit Unterstützung für die Couroutinen TS. Eine Liste der unterstützten Compiler und Versionen finden Sie in der Dokumentation.
Dokumentation
QCoro bietet die notwendigen Tools für die einfache Nutzung von C++20-Coroutinen mit Qt. Der Eckpfeiler der Bibliothek ist QCoro::Task<T>
, das eine ausgeführte Coroutine darstellt und es dem Aufrufer ermöglicht, asynchron auf das Ergebnis der Coroutine zu warten. Darüber hinaus bietet QCoro eine Reihe von Wrappern für gängige Qt-Typen wie QTimer
, QNetworkReply
, QDBusPendingCall
, QFuture
und andere, die es ermöglichen, ihre asynchronen Vorgänge direkt zu co_await
.
Darüber hinaus gibt es eine magische qCoro()
Funktion, die viele native Qt-Funktionen und -Typen umschließen kann, um sie Coroutine-freundlich zu machen.
Sehen Sie sich die Dokumentation an, um eine vollständige Liste aller unterstützten Funktionen und Qt-Typen zu erhalten.
QDBusPendingCall
QCoro kann warten, bis ein asynchroner D-Bus-Aufruf abgeschlossen ist. Es ist nicht erforderlich, QDBusPendingCallWatcher
mit QCoro zu verwenden – co_await
stattdessen einfach das Ergebnis. Während co_awaiting läuft die Qt-Ereignisschleife wie gewohnt.
QDBusInterface remoteServiceInterface{serviceName, objectPath, interface};const QDBusReply<bool> isReady = co_await remoteServiceInterface.asyncCall(QStringLiteral("isReady"));
Vollständige Dokumentation hier.
QFuture
QFuture stellt ein Ergebnis einer asynchronen Aufgabe dar. Normalerweise müssen Sie QFutureWatcher
verwenden, um benachrichtigt zu werden, wenn die Zukunft bereit ist. Mit QCoro können Sie es einfach co_await
!
const QFuture<int> task1 = QtConcurrent::run(....);const QFuture<int> task2 = QtConcurrent::run(....);const int a = co_await task1;const int b = co_await task2; co_return a + b;
Vollständige Dokumentation hier.
QNetworkReply
Das Ausführen von Netzwerkanfragen mit Qt kann mühsam sein – der Signal-/Slot-Ansatz unterbricht den Fluss Ihres Codes. Das Verketten von Anfragen und die Fehlerbehandlung werden schnell zu einem Chaos und Ihr Code wird in zahlreiche Funktionen zerlegt. Aber nicht mit QCoro, wo Sie einfach co_await
, bis die QNetworkReply
fertig ist:
QNetworkAccessManager qnam; QNetworkReply *reply = qnam.get(QStringLiteral("https://github.com/qcoro/qcoro"));const auto content = co_await reply; reply->deleteLater();if (reply->error() != QNetworkReply::NoError) {co_return handleError(reply); }const auto link = findLinkInReturnedHtmlCode(contents); Reply = qnam.get(link);const auto data = co_await Reply; reply->deleteLater();if (reply->error() != QNetworkReply::NoError) {co_return handleError(reply); } ...
Vollständige Dokumentation hier.
QTimer
Vielleicht möchten Sie die Ausführung Ihres Codes um eine Sekunde verzögern, vielleicht möchten Sie einen Code in wiederholten Abständen ausführen. Mit co_await
wird das supertrivial:
QTimer-Timer; timer.setInterval(1s); timer.start();for (int i = 1; i <= 100; ++i) {co_await timer;qDebug() << "Warten auf " << i << " Sekunden..."; }qDebug() << "Fertig!";
Vollständige Dokumentation hier.
QIODevice
QIODevice
ist eine Basisklasse für viele Klassen in Qt, die das asynchrone Schreiben und Lesen von Daten ermöglichen. Wie finden Sie heraus, dass Daten zum Lesen bereitstehen? Sie können eine Verbindung zum QIODevice::readyRead()
herstellen oder QCoro verwenden und das Objekt co_await
:
socket->write("PING");// Warten auf "pong"const auto data = co_await socket;co_return berechneLatency(data);
Vollständige Dokumentation hier.
Sehen Sie sich die vollständige Dokumentation an, um mehr zu erfahren.
Manchmal ist es nicht möglich, co_await
zu verwenden, um das Ergebnis einer Coroutine zu verarbeiten – normalerweise, wenn eine Schnittstelle zu Code eines Drittanbieters besteht, der keine Coroutinen unterstützt. In diesen Szenarien ist es möglich, einen Fortsetzungsrückruf an die Coroutine zu verketten, der asynchron aufgerufen wird, wenn die Coroutine beendet ist.
void regularFunction() {someCoroutineReturningInt().then([](int result) {// handle result}); }
Der Fortsetzungsrückruf kann auch eine Coroutine sein und das Ergebnis des gesamten Ausdrucks ist Task, wobei T der Rückgabetyp der Fortsetzung ist. Dadurch ist es möglich, die gesamte Kette co_await
oder mehrere .then()
-Fortsetzungen zu verketten.
Vollständige Dokumentation hier.
Generator ist eine Coroutine, die träge mehrere Werte erzeugt. Obwohl es nichts Qt-spezifisches gibt, stellt QCoro den Benutzern die notwendigen Tools zur Verfügung, um benutzerdefinierte Generatoren in ihren Qt-Anwendungen zu erstellen.
QCoro bietet eine API sowohl für Synchrongeneratoren ( QCoro::Generator<T>
) als auch für Asynchrongeneratoren ( QCoro::AsyncGenerator<T>
). Beide Generatoren bieten eine Container-ähnliche API: die Memberfunktionen begin()
und end()
, die iteratorähnliche Objekte zurückgeben. Dies ist eine bekannte und etablierte API und macht Generatoren mit vorhandenen Algorithmen kompatibel.
QCoro::Generator<int> fibonacci() { quint64 a = 0, b = 0; Q_FOREVER {co_yield b;const auto tmp = b; a = b; b += tmp; } }void printFib(quint64 max) {for (auto fib : fibonacci()) {if (fib > max) {break; } std::cout << fib << std::endl; } }
Vollständige Dokumentation hier.
MIT License
Copyright (c) 2022 Daniel Vrátil <[email protected]>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.