Mimariye derinden bağlı olay sistemi ve sinyal yuvası mekanizmasıyla Qt çerçevesi, geliştiricileri her zaman eşzamansız programlamada desteklemiştir. Serimizin önceki bölümünde bu seçenekler sunuldu.
Duyurudan sonra devamını okuyun
Martin Meeser bağımsız bir bilgisayar bilimcisidir (üniversite) ve yazılım geliştirme alanında hizmetler sunmaktadır: bireysel yazılım geliştirme, süreç danışmanlığı ve eğitim. Otomotiv, finans, uzay yolculuğu, radyo astronomi ve tıbbi teknoloji sektörleri de dahil olmak üzere çok sayıda projede müşterilerine destek vermiştir.
QFuture, “o zaman yapılabilir” kavramını içeren daha yeni bir Qt yapısıdır. .then()-Methods – diğer dillerden (örneğin, JavaScript'te Promise, Java'da CompletebleFuture veya C#'ta Task). Şununla izin verir: QFuture::then() Örneğin kullanıcı arayüzlerini eşzamansız olarak güncellemek için eşzamansız, iş parçacığından bağımsız işlevleri yürütün ve basamaklandırın.
Qt'de QFuture'ı okumak ve tüketmek her zaman aynı madalyonun iki yüzü gibi görünür. Yazma ve prodüksiyon tarafında QPromise var. Geliştiriciler Promise-Future çiftinin durumunu ayrıntılı olarak kontrol edebilirler: start (QPromise::start()), askıya almak (QPromise::suspend()), son (QPromise::finish()) veya iptal edin (QPromise::cancel()). Son olarak, geliştiriciler yalnızca bir dönüş değeri değil, herhangi bir sayıyı (QPromise::addResult()). QPromise/QFuture API ile kullanıcı ve mantık katmanlarını etkili bir şekilde ayırmak ve ilerlemeyi kullanıcı arayüzüne raporlamak için kullanışlı bir arayüze sahip olursunuz.
sınıf QFutureWatcher QFuture işlevselliğini önceki makalede açıklanan sinyal/yuva mekanizmasına bağlamak için bir mekanizma sağlar. Aşağıdaki Liste 1'de temel işlevlerin bir örneği gösterilmektedir.
int main(int argc, char* argv[])
{
QCoreApplication app(argc, argv);
QFutureWatcher<int> watcher;
QObject::connect(&watcher, &QFutureWatcher<int>::started, []()
{
qInfo() << "future started ";
});
QObject::connect(&watcher, &QFutureWatcher<int>::resultReadyAt, [&watcher](int i)
{
qInfo() << "result ready" << i << "=" << watcher.future().resultAt(i);
});
QObject::connect(&watcher, &QFutureWatcher<int>::finished, [&watcher, &app]()
{
qInfo() << "future finished ";
for (int i = 0; i < watcher.future().resultCount(); ++i)
{
qInfo() << "Final result" << i << "=" << watcher.future().resultAt(i);
}
app.quit();
});
QPromise<int> promise;
QFuture<int> future = promise.future();
watcher.setFuture(future);
QThreadPool::globalInstance()->start([&promise]()
{
promise.start();
QThread::sleep(1);
promise.addResult(10);
QThread::sleep(1);
promise.addResult(20);
QThread::sleep(1);
promise.finish();
});
return app.exec();
}
Liste 1: QPromise, QFuture ve QFutureWatcher kullanımına ilişkin basit örnek.
Duyurudan sonra devamını okuyun
Yanında QFutureWatcher sınıf teklifleri QFuture Vadeli işlemleri birbiri ardına bağlamak için akıcı bir API (yukarıda bahsedilen “sonradan yapılabilir” veya aynı zamanda “zincirleme” olarak da adlandırılır): geliştiriciler dahil olur then() ikinci bir kullanımla bir halef then() önceki halefin üzerine yazar, böylece yalnızca bir halef olabilir. Ayrıca ilk kullanım addResult altta yatan vaadin then() dışarıda ve ilgili değil promise.finish(). Taahhütün iptali cancel() geri aramayı etkinleştir onCancelled (aşağıdaki Liste 2'ye bakın).
int main(int argc, char* argv[])
{
QCoreApplication app(argc, argv);
QPromise<int> promise;
QFuture<int> future = promise.future();
QThreadPool::globalInstance()->start([&promise]()
{
promise.start();
qInfo() << QDateTime::currentDateTime().toString(Qt::ISODateWithMs) << QThread::currentThreadId() << "started";
QThread::sleep(1);
promise.addResult(1); // triggert then()
QThread::sleep(1);
// promise.cancel(); // triggert onCanceled()
promise.addResult(2); // kein Effekt auf then()
promise.finish();// kein Effekt auf then()
});
future
.onCanceled([]{/*...*/ return -1;})
.then([](int result1)
{
qInfo() << QDateTime::currentDateTime().toString(Qt::ISODateWithMs) << QThread::currentThreadId() << "result" << result1;
});
return app.exec();
}
Liste 2: Then() ve onCancelled()'ı etkinleştirme örneği.
Yöntem then() hem parametre hem de dönüş değeri için geneldir. Bu özellikle ne anlama geliyor? QFuture<T> onda var then– Bir tür parametresi çağrılabilir T. Geliştiricinin dosya içinde kullandığı dönüş türü then-Çağrılabilir, geleceğin geri dönüş türüdür ve bu da sağlanır then() zincirleme sırayla asılabilir, bkz. Liste 3:
void myFunc(QString val){/*...*/ return;}
QFuture<int> future = // siehe Listing 12
QFuture<void> future2 = future.then([](int result1)
{
return QString("fortytwo");
}).then(myFunc);
Liste 3: Then() ile gelecekteki zincirlemeye örnek.
Eğer gelecekte veya then()-Bir istisnanın oluşmasını engeller, geri aramaya gönderilir onFailed() doğrudan. Kural, istisnanın uygun olanı bulana kadar zincirde daha aşağıya doğru ilerlemesidir. onFailed-Geri aramaya ulaşıldı. Program parçalarını çalışan iş parçacıklarına taşırsanız, istisnaları doğru şekilde yakalayıp yanıtlamanız gerekir. promise.setException() devretmek. Yöntem ancak o zaman işe yarayacaktır onFailed beklendiği gibi, bkz. Liste 4:
QThreadPool::globalInstance()->start([&promise]()
{
promise.start();
try
{
throw std::runtime_error("error from f1");
promise.addResult(42); // das wird nicht erreicht
}
catch (const std::exception& ex)
{
promise.setException(std::current_exception());
}
});
future.then([](int i)
{
// ...
}).onFailed([](const std::exception& ex)
{
qInfo() << ex.what();
});
QTimer::singleShot(200, &app, &QCoreApplication::quit);
Liste 4: Promise ile çalışan iş parçacıklarındaki istisnaları doğru şekilde işleme.
Geliştiriciler ayrıca birkaç tane yapabilir onFailed bir gelecekle kullanın. Bu durumda ilk muhabir aranır. Sıra uygundur: örneğin Liste 5'te ikinci onFailed asla başarılamadı çünkü bir öncekinde üst sınıf zaten ele geçirilmişti.
future.then([](int res) {
// ...
throw std::runtime_error("Exception");
}).onFailed([](const std::exception &e) {
// dieses Callback wird ausgeführt
}).onFailed([](const std::runtime_error &e) {
});
Liste 5: Birden fazla onFailed geri arama kullanma
Bu fonksiyonun içinde onFailed işlendiğinde geliştiriciler bir dönüş değeri de belirtebilir. Zincir daha sonra bu değerle devam eder, bkz. Liste 6:
QFuture<int> future = ...
future
.onFailed([](const QException& ex)
{
return -1;
})
.then([](int i)
{
// im Fehlerfall ist i=-1
})
Liste 6: Hata durumunda Then() zincirine devam edilir.
Yeterli geri aramanın olmaması durumunda onFailed mevcutsa, istisna, oluştuğu iş parçacığından çağıran iş parçacığına iletilir ve buna göre yakalanması gerekir (hata yayılımı), bkz. Liste 7:
auto resultFuture = future.then([](int res) {
...
throw Error("message");
...
}).onFailed([](const std::exception &e) {
// wird nicht aufgerufen
}).onFailed([](const QException &e) {
// wird nicht aufgerufen
});
try {
auto result = resultFuture.result();
} catch(Error er) {
// dieser Teil wird aufgerufen
}
Liste 7: Bir İstisnanın Yayılması.
Şu ana kadar gösterilen kullanım then() Varsayılan olarak, orijinalin bulunduğu iş parçacığında sonraki işlevleri yürütür QFuture kurs. Geliştiriciler ayrıca bir sonraki işlevin iş parçacığını belirlemek için bir parametre kullanabilirler. Bunu parametre olarak iletin QObjectilişkili QThread kullanılır. birde QThreadPoolbu kullanılıyor.
Son olarak geliştiriciler bir tür argümanı da kullanabilirler QtFuture::Launch teslim edildi: ileri tespit Sync açıklanan standart duruma karşılık gelir (arayanla aynı konu), oysa Async otomatik olarak global iş parçacığı havuzunu kullanır e Inherit önceki ayar, bkz. Liste 8:
// Standardfall, kein Parameter, entspricht Sync)
auto f1 = base.then([](int i) { ... });
auto f2 = f1.then(QtFuture::Launch::Sync, [](int i) { ... });
// QObject => Ausführung im Thread des QObjects
auto f3 = f1.then(&obj, [](int i) { ... });
// QThreadPool => Ausführung im angegebenen Pool
auto f4 = f2.then(&customPool, [](int i) { ... });
// Launch::Async => globaler Threadpool
auto f5 = f4.then(QtFuture::Launch::Async, [](int i) { ... });
// Launch::Inherit: erbt Thread des Vorgängers
auto f6 = f5.then(QtFuture::Launch::Inherit, [](int i) { … });
Liste 8: Then(…) ile ipliğin belirlenmesi
Ad alanı QtFuture Ayrıca vadeli işlemler için bazı yararlı yardım fonksiyonları da içerir. Fonksiyonlarla QtFuture::makeReady… Geliştiriciler eyalette zaten bitmiş bir gelecek yaratırlar (QFuture.isFinished() teslimat true). makeReadyVoidFuture hiçbir değeri olmayan sınırlı bir gelecek yaratır (QFuture<void>), makeReadyValueFuture(T) sonuç olarak QFuture<T> VE makeReadyRangeFuture biri bitti QFuture<T>hangisinin daha fazla sonucu var. makeExceptionalFuture sonunda bir istisna içeren sonlandırılmış bir QFuture yaratır.
QFuture gibi düzenlemenin mümkün veya yararlı olup olmadığını test etmek için parametreler kullanmak istiyorsanız bu işlevler kullanışlıdır. Aksi halde, işlev doğrudan sonlandırılmış bir QFuture döndürür, bkz. Liste 9:
QFuture<int> createIntFuture(int a)
{
if (a <= 0)
{
return QtFuture::makeReadyValueFuture(0);
}
QPromise<int> promise;
QFuture<int> result = promise.future();
QThreadPool::globalInstance()->start([promise = std::move(promise), a]() mutable
{
promise.start();
QThread::sleep(500);
promise.addResult(a + 1);
promise.finish();
});
}
Liste 9: makeReadyValueFuture ile oluşturmada sınırlı bir geleceğin kullanılması.
Bir diğer kullanışlı özellik ise QtFuture::whenAll()O QFuture oluşturulur ve tümü parametre olarak iletildiğinde sonlandırılır. QFuture onlar bitti. THE QFuture farklı model türleri olabilir, bu nedenle dönüş türü whenAll A QFuture türlerin bir listesi ile std::variant.
Geliştiricilerin hala zincirlemeyle ilgili tuhaflığa dikkat etmeleri gerekiyor then() ardıl işlev, geleceği en son biten iş parçacığında yürütülür. Daha önce açıklandığı gibi bu, aşağıdakiler için bir parametre olabilir: then() açıkça belirtin, bkz. Liste 10:
QFuture<int> f_int = createIntFuture();
QFuture<QString> f_qstring = createStringFuture();
QFuture<void> f_void = createVoidFuture();
using MyFuturesVariant = std::variant<QFuture<int>, QFuture<QString>, QFuture<void>>;
QFuture<QList<MyFuturesVariant>> f_whenAll = QtFuture::whenAll(f_int, f_qstring, f_void);
f_whenAll.then(/*QtFuture::Launch::Async*/, [](const
QList<MyFuturesVariant>& results)
{
...
});
Liste 10: QtFuture::whenAll(…) Örnek
QtFuture::whenAny() bir tane üretir QFuturegeçmiş geleceklerden biri hazır olur olmaz sona erer. Zincirleme sırasında ardıl işlev, açık bir başlatma parametresi aksini belirtmediği sürece, ilk sonlandırılan geleceğin iş parçacığı üzerinde yürütülür, bkz. Liste 11:
QFuture<MyFuturesVariant> f_whenAny = QtFuture::whenAny(f_int, f_qstring, f_void);
f_whenAny.then([](const MyFuturesVariant& f)
{
});
Liste 11: QtFuture Örnek::whenAny(…)
Son olarak, fonksiyon şunu sağlar: QtFuture::connect() herhangi bir sinyali seçebilme yeteneği QFuture oluşturmak için Liste 12'ye bakın:
QTimer timer(&app);
timer.setInterval(1000);
timer.setSingleShot(true);
timer.start();
QFuture<void> timerTimeoutFuture = QtFuture::connect(&timer, &QTimer::timeout);
timerTimeoutFuture.then([]
{
qDebug() << "QTimer timeout captured via QtFuture::connect";
});
Liste 12: QtFuture::connect() Kullanım Örneği

Bir yanıt yazın