A biblioteca QCoro fornece um conjunto de ferramentas para fazer uso de corrotinas C++20 com Qt.
Dê uma olhada no exemplo abaixo para ver como as corrotinas são incríveis:
QNetworkAccessManager networkAccessManager;// co_await a resposta - a corrotina é suspensa até que o QNetworkReply seja concluído. // Enquanto a corrotina está suspensa, *o loop de eventos Qt é executado normalmente*.const QNetworkReply *reply = co_await networkAccessManager.get(url); // Assim que a resposta for concluída, seu código será retomado aqui como se nada de incrível tivesse acontecido ;-)const auto data = responder->lerTodos();
Requer um compilador com suporte para TS couroutines, consulte a documentação para obter uma lista de compiladores e versões suportadas.
Documentação
QCoro fornece as ferramentas necessárias para facilitar o uso de corrotinas C++20 com Qt. A base da biblioteca é QCoro::Task<T>
, que representa uma corrotina executada e permite que o resultado da corrotina seja aguardado de forma assíncrona por seu chamador. Além disso, QCoro fornece um conjunto de wrappers para tipos comuns de Qt, como QTimer
, QNetworkReply
, QDBusPendingCall
, QFuture
e outros, que permitem co_await
suas operações assíncronas diretamente.
Além disso, há uma função mágica qCoro()
que pode agrupar muitas funções e tipos nativos do Qt para torná-los compatíveis com a rotina.
Verifique a documentação para obter uma lista completa de todos os recursos suportados e tipos de Qt.
QDBusPendingCall
QCoro pode esperar o término de uma chamada assíncrona do D-Bus. Não há necessidade de usar QDBusPendingCallWatcher
com QCoro - apenas co_await
o resultado. Enquanto co_awaiting, o loop de eventos do Qt é executado normalmente.
QDBusInterface remoteServiceInterface{serviceName, objectPath, interface};const QDBusReply<bool> isReady = co_await remoteServiceInterface.asyncCall(QStringLiteral("isReady"));
Documentação completa aqui.
QFuture
QFuture representa o resultado de uma tarefa assíncrona. Normalmente você precisa usar QFutureWatcher
para ser notificado quando o futuro estiver pronto. Com o QCoro, você pode simplesmente 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_retorno a + b;
Documentação completa aqui.
QNetworkReply
Fazer solicitações de rede com Qt pode ser entediante - a abordagem sinal/slot interrompe o fluxo do seu código. O encadeamento de solicitações e o tratamento de erros rapidamente se tornam uma bagunça e seu código é dividido em inúmeras funções. Mas não com o QCoro, onde você pode simplesmente co_await
o QNetworkReply
terminar:
QNetworkAccessManagerqnam; QNetworkReply *reply = qnam.get(QStringLiteral("https://github.com/qcoro/qcoro"));const auto content = co_await resposta; resposta->deleteLater();if (resposta->error() != QNetworkReply::NoError) {co_return handleError(resposta); }const link automático = findLinkInReturnedHtmlCode(conteúdo); resposta = qnam.get(link);const auto data = co_await resposta; resposta->deleteLater();if (resposta->error() != QNetworkReply::NoError) {co_return handleError(resposta); } ...
Documentação completa aqui.
QTimer
Talvez você queira atrasar a execução do seu código por um segundo, talvez queira executar algum código em intervalos repetidos. Isso se torna supertrivial com co_await
:
Temporizador QTimer; temporizador.setInterval(1s); timer.start();for (int i = 1; i <= 100; ++i) {co_await timer;qDebug() << "Aguardando " << i << " segundos..."; }qDebug() << "Concluído!";
Documentação completa aqui.
QIODevice
QIODevice
é uma classe base para muitas classes em Qt que permitem que os dados sejam escritos e lidos de forma assíncrona. Como você descobre que existem dados prontos para serem lidos? Você pode se conectar ao QIODevice::readyRead()
singal ou usar QCoro e co_await
o objeto:
socket->write("PING");// Aguardando "pong"const auto data = co_await socket;co_return calculaLatência(dados);
Documentação completa aqui.
Verifique a documentação completa para saber mais.
Às vezes não é possível usar co_await
para lidar com o resultado de uma corrotina - geralmente ao fazer interface com um código de terceiros que não suporta corrotinas. Nesses cenários, é possível encadear um retorno de chamada de continuação à corrotina que será invocada de forma assíncrona quando a corrotina terminar.
void regularFunction() {someCoroutineReturningInt().then([](resultado int) {// lidar com resultado}); }
O retorno de chamada de continuação também pode ser uma corrotina e o resultado de toda a expressão é Task onde T é o tipo de retorno da continuação. Graças a isso é possível co_await
toda a cadeia, ou encadear múltiplas continuações .then()
.
Documentação completa aqui.
Generator é uma corrotina que produz vários valores preguiçosamente. Embora não haja nada específico do Qt, o QCoro fornece as ferramentas necessárias para os usuários criarem geradores personalizados em seus aplicativos Qt.
QCoro fornece API para geradores síncronos ( QCoro::Generator<T>
) e geradores assíncronos ( QCoro::AsyncGenerator<T>
). Ambos os geradores fornecem API semelhante a contêiner: funções de membro begin()
e end()
que retornam objetos semelhantes a iteradores, que é uma API bem conhecida e estabelecida e torna os geradores compatíveis com algoritmos existentes.
QCoro::Generator<int>fibonacci() { quint64 a = 0, b = 0; Q_FOREVER {co_rendimento b;const auto tmp = b; uma =b; b += tmp; } }void printFib(quint64 max) {for (auto fib: fibonacci()) {if (fib > max) {break; } std::cout << fib << std::endl; } }
Documentação completa aqui.
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.