Tasking::TaskTree Class
class Tasking::TaskTreeKlasa TaskTree pokreće asinkronu strukturu stabla zadataka definiranu na deklarativan način. Više...
| Header: | #include <solutions/tasking/tasktree.h> |
| Inherits: | QObject |
Napomena: Sve funkcije u ovoj klasi su reentrantne.
Javne funkcijeJavne funkcije
| TaskTree(QObject *parent = nullptr) | |
| TaskTree(const Tasking::Group &recipe, QObject *parent = nullptr) | |
| virtual | ~TaskTree() |
| int | asyncCount() const |
| void | cancel() |
| bool | isRunning() const |
| void | onStorageDone(const Tasking::Storage<StorageStruct> &storage, Handler &&handler) |
| void | onStorageSetup(const Tasking::Storage<StorageStruct> &storage, Handler &&handler) |
| int | progressMaximum() const |
| int | progressValue() const |
| Tasking::DoneWith | runBlocking() |
| Tasking::DoneWith | runBlocking(const QFuture<void> &future) |
| void | setRecipe(const Tasking::Group &recipe) |
| void | start() |
| int | taskCount() const |
Signali
| void | asyncCountChanged(int count) |
| void | done(Tasking::DoneWith result) |
| void | progressValueChanged(int value) |
| void | started() |
Stalni javni članovi
| Tasking::DoneWith | runBlocking(const Tasking::Group &recipe) |
| Tasking::DoneWith | runBlocking(const Tasking::Group &recipe, const QFuture<void> &future) |
Detaljan opis
Koristite imenski prostor Tasking za izgradnju proširivih, deklarativnih stablastih struktura zadataka koje mogu sadržavati asinkrone zadatke, kao što su QProcess, NetworkQuery ili ConcurrentCall<ReturnType>. Strukture TaskTree omogućuju vam stvaranje sofisticirane mješavine paralelnog ili sekvencijalnog toka zadataka u obliku stabla i pokretanje u bilo kojem trenutku kasnije.
Korisnička definicija Korištenje imenog prostora Tasking za izgradnju proširivih, deklarativnih struKoren elementa i zadaci
Detaljan opisKoristite imenski prostor Tasking za izgradnju proširivih, deklarativnih struktura stabTaskTree ima obavezni korijenski element Group, koji može sadržavati bilo koji broj zadataka različitih vrsta, kao što su QProcessTask, NetworkQueryTask ili ConcurrentCallTask<ReturnType>:
using namespace Tasking; const Group root { QProcessTask(...), NetworkQueryTask(...), ConcurrentCallTask<int>(...) }; TaskTree *taskTree = new TaskTree(root); connect(taskTree, &TaskTree::done, ...); // finish handler taskTree->start();
Gornje stablo zadataka ima element najviše razine tipa Group koji sadrži zadatke tipova QProcessTask, NetworkQueryTask i ConcurrentCallTask<int>. Nakon poziva metode taskTree->start(), zadaci se izvršavaju u nizu, počevši od QProcessTask-a. Kada se QProcessTask uspješno završi, pokreće se zadatak NetworkQueryTask. Na kraju, kada mrežna zadatka završi uspješno, pokreće se zadatak ConcurrentCallTask<int>.
Kada se posljednji aktivni zadatak uspješno završi, stablo zadataka smatra se uspješno izvršenim i signal done() se emitira s argumentom DoneWith::Success. Kada se zadatak završi s greškom, izvršavanje stabla zadataka se zaustavlja i preostali zadaci se preskaču. Stablo zadataka završava s greškom i šalje signal TaskTree::done() s argumentom DoneWith::Error.
Grupe
Roditelj grupe vidi je kao jedan zadatak. Kao i drugi zadaci, grupa se može pokrenuti i može završiti uspješno ili s pogreškom. Elementi grupe mogu se ugniježđivati kako bi se stvorila stablo struktura:
const Group root { Group { parallel, QProcessTask(...), ConcurrentCallTask<int>(...) }, NetworkQueryTask(...) };
Gornji primjer razlikuje se od prvog primjera po tome što korijenski element ima podgrupu koja sadrži QProcessTask i ConcurrentCallTask<int>. Podgrupa je sestrinski element NetworkQueryTask-a u korijenu. Podgrupa sadrži dodatni paralelni element koji nalaže svojoj Grupi da izvršava svoje zadatke paralelno.
Dakle, kada se pokrene gornje stablo, QProcessTask i ConcurrentCallTask<int> odmah se pokreću i izvršavaju se paralelno. Budući da korijenska grupa ne sadrži paralelni element, njezini se zadaci izravnih podređenih elemenata izvršavaju slijedom. Tako se NetworkQueryTask pokreće kada cijela podgrupa završi. Grupa se smatra završenom kada svi njezini zadaci završe. Redoslijed u kojem zadaci završavaju nije bitan.
Dakle, ovisno o tome koji zadatak traje dulje (QProcessTask ili ConcurrentCallTask<int>), mogu se doDakle, ovisno o tome koji zadatak traje dulje (QProcessTask ili ConcurrentCallTask<int>), mogu se dogoditi sljedeći scenariji:
| Scenarij 1 | Scenarij 2 |
|---|---|
| Root Group započinje | Korijenska grupa započinje |
| Podgrupa započinje | Podgrupa započinje |
| QProcessTask započinje | QProcessTask započinje |
| ConcurrentCallTask<int> započinje | ConcurrentCallTask<int> započinje |
| ... | ... |
| QProcessTask završava | ConcurrentCallTask<int> završava |
| ... | ... |
| ConcurrentCallTask<int> završava | QProcessTask završava |
| Podgrupa završava | Podgrupa završava |
| NetworkQueryTask započinje | NetworkQueryTask započinje |
| ... | ... |
| NetworkQueryTask završava | NetworkQueryTask završava |
| Korenjska grupa završava | Korenjska grupa završava |
Razlike između scenarija označene su podebljanim slovima. Tri točke znače da između prethodnog i sljedećeg događaja prolazi neodređeno vrijeme (zadatak ili zadaci se nastavljaju izvršavati). Nema točaka između događaja znači da se oni odvijaju sinkrono.
Predstavljeni scenariji pretpostavljaju da se svi zadaci uspješno izvršavaju. Ako zadatak tijekom izvršavanja zakaže, stablo zadataka završava s pogreškom. Posebno, kada QProcessTask završi s pogreškom dok se ConcurrentCallTask<int> još uvijek izvršava, ConcurrentCallTask<int> se automatski otkazuje, podskupina završava s pogreškom, NetworkQueryTask se preskače i stablo završava s pogreškom.
Vrste zadataka
Svaka vrsta zadatka povezana je sa svojom odgovarajućom klasom zadataka koja izvršava zadatak. Na primjer, QProcessTask unutar stabla zadataka povezan je s klasom QProcess koja izvršava proces. Povezani objekti automatski se stvaraju, pokreću i uništavaju isključivo od strane stabla zadataka u odgovarajućem trenutku.
Vrste zadatakaSvaka vrsta zadatka povezana je sa svojom odgovarajućom klasom zadataka koja izvršavaAko se korijenska grupa sastoji od pet uzastopnih zadataka QProcessTask, a stablo zadataka izvršava grupu, ono stvara instancu klase QProcess za prvi QProcessTask i pokreće ga. Ako se instanca klase QProcess uspješno završi, stablo zadataka je uništava i stvara novu instancu klase QProcess za drugi QProcessTask, i tako dalje. Ako se prvi zadatak završi s pogreškom, stablo zadataka prestaje stvarati instance klase QProcess, a korijenska grupa završava s pogreškom.
Sljedeća tablica prikazuje primjere tipova zadataka i njihovih odgovarajućih klasa zadataka:Sljedeća tablica prikazuje primjere vrsta zadataka i njihovih odgovarajućih klasa zadataka:
| Tip zadatka (Tasking Namespace) | Povezana klasa zadatka | Kratki opis |
|---|---|---|
| QProcessTask | QProcess | Pokreće proces. |
| ConcurrentCallTask<ReturnType> | Tasking::ConcurrentCall<ReturnType> | Pokreće asinkroni zadatak, izvršava se u zasebnom niti. |
| TaskTreeTask | Tasking::TaskTree | Pokreće ugniježđeno stablo zadataka. |
| NetworkQueryTask | Upit mreže | Pokreće mrežno preuzimanje. |
Obrađivači zadataka
Koristite rukovatelje zadataka za postavljanje zadatka za izvršavanje i omogućavanje čitanja izlaznih podataka iz zadatka kada se on završi uspješno ili s pogreškom.
Početni rukovatelj zadatka
Kada se stvori odgovarajući objekt klase zadatka i prije nego što se pokrene, stablo zadataka poziva opcionalno korisnikom osiguranog upravljača za postavljanje. Upravljač za postavljanje uvijek bi trebao uzeti referencu na povezani objekt klase zadatka:
const auto onSetup = [](QProcess &process) { process.setProgram("sleep"); process.setArguments({"3"}); }; const Group root { QProcessTask(onSetup) };
Možete izmijeniti proslijeđeni QProcess u setup handleru, kako bi stablo zadataka moglo pokrenuti proces prema vašoj konfiguraciji. Ne biste trebali pozvati process.start(); u setup handleru, jer ga stablo zadataka poziva kada je potrebno. Setup handler je neobavezan. Kada se koristi, mora biti prvi argument konstruktora zadatka.
Po želji, setup handler može vratiti SetupResult. Vraćeni SetupResult utječe na daljnje ponašanje pri pokretanju zadane zadatke. Moguće vrijednosti su:
| SetupResult Vrijednost | Kratki opis |
|---|---|
| Nastavi | Zadatak će se pokrenuti normalno. To je zadano ponašanje kada rukovatelj postavki ne vrati SetupResult (tj. njegov tip povrata je void). |
| StopWithSuccess | Zadatak neće biti pokrenut i izvijestit će o uspjehu svom roditelju. |
| StopWithError | Zadatak neće biti pokrenut i izvijestit će o pogrešci svom roditelju. |
Ovo je korisno za pokretanje zadatka samo kada je zadovoljena određena uvjetna, a podaci potrebni za procjenu tog uvjeta nisu poznati dok prethodno pokrenuti zadaci ne završe. Na taj način, upravljački program za postavljanje dinamički odlučuje hoće li normalno pokrenuti odgovarajući zadatak ili ga preskočiti i izvijestiti o uspjehu ili pogrešci. Za više informacija o razmjeni podataka između zadataka pogledajte Storage.
Rukovatelj dovršetka zadatka
Kada se pokrenuta zadatka završi, stablo zadataka poziva opcionalno navedeni rukovatelj završetka. Rukovatelj bi trebao primiti referencu na const povezani objekt klase zadatka:
const auto onSetup = [](QProcess&process) { process.setProgram("sleep"); process.setArguments({"3"}); }; const auto onDone = [](const QProcess&process, DoneWith result) { if (result== DoneWith::Success) qDebug() << "Success" << process.cleanedStdOut(); inače qDebug() << "Failure" << process.cleanedStdErr(); }; const Group root { QProcessTask(onSetup, onDone) };
Rukovatelj događaja 'done' može prikupiti izlazne podatke iz QProcess-a i pohraniti ih za daljnju obradu ili izvršiti dodatne radnje.
Napomena: Ako handler za postavljanje zadatka vrati StopWithSuccess ili StopWithError, handler za završetak se neće pozvati.
Grupni rukovatelji
Slično upravljačima zadataka, upravljači grupa omogućuju vam postavljanje grupe za izvršavanje i primjenu dodatnih radnji kada cijela grupa završi uspješno ili s pogreškom.
Početni rukovatelj grupe
Drvo zadataka poziva rukovatelja početka grupe prije nego što pokrene podređene zadatke. Rukovatelj grupe ne prima nikakve argumente:
const auto onSetup = [] { qDebug() << "Entering the group"; }; const Group root { onGroupSetup(onSetup), QProcessTask(...) };
Rukovatelj postavljanja grupe je neobavezan. Da biste definirali rukovatelj postavljanja grupe, dodajte element onGroupSetup() u grupu. Argument funkcije onGroupSetup() je korisnički rukovatelj. Ako u grupu dodate više od jednog elementa onGroupSetup(), tijekom izvođenja se pokreće assert koji uključuje poruku o pogrešci.
Kao i rukovatelj početkom zadatka, rukovatelj početkom grupe može vratiti xml-ph-0000@deepl.internalPoput rukovatelja početkom zadatka, rukovatelj početkom grupe može vratiti SetupResult. Vraćena vrijednost SetupResult utječe na ponašanje pri pokretanju cijele grupe. Ako ne navedete rukovatelja početkom grupe ili je njegov tip povrata void, zadano djelovanje grupe je SetupResult::Continue, tako da se svi zadaci pokreću normalno. Inače, kada rukovatelj početkom vrati SetupResult::StopWithSuccess ili SetupResult::StopWithError, zadaci se ne pokreću (preskaču se) i sama grupa prijavljuje uspjeh ili neuspjeh, ovisno o vraćenoj vrijednosti.
const Group root { onGroupSetup([] { qDebug() << "Root setup"; }), Group { onGroupSetup([] { qDebug() << "Group 1 setup"; return SetupResult::Continue; }), QProcessTask(...) // Process 1 }, Group { onGroupSetup([] { qDebug() << "Group 2 setup"; return SetupResult::StopWithSuccess; }), QProcessTask(...) // Process 2 }, Group { onGroupSetup([] { qDebug() << "Group 3 setup"; return SetupResult::StopWithError; }), QProcessTask(...) // Process 3 }, QProcessTask(...) // Process 4 };
U gornjem primjeru sve podgrupe korijenske grupe definiraju svoje rukovatelje postavljanja. Sljedeći scenarij pretpostavlja da se svi pokrenuti procesi završe uspješno:
| Scenarij | Komentari |
|---|---|
| Pokretanje korijenske grupe | Ne vraća SetupResult, pa se njegovi zadaci izvršavaju. |
| Grupa 1 započinje | Vraća Continue, pa se njegovi zadaci izvršavaju. |
| Proces 1 započinje | |
| ... | ... |
| Proces 1 završava (uspješno) | |
| Grupa 1 završava (uspješno) | |
| Grupa 2 započinje | Vraća StopWithSuccess, pa se Proces 2 preskače i Grupa 2 prijavljuje uspjeh. |
| Grupa 2 završava (uspješno) | |
| Grupa 3 započinje | Vraća StopWithError, pa se Proces 3 preskače i Grupa 3 prijavljuje pogrešku. |
| Grupa 3 završava (greška) | |
| Korisnička grupa završava (greška) | Grupa 3, koja je izravno dijete korijenske grupe, završila je s pogreškom, pa korijenska grupa prekida izvršavanje, preskače Proces 4 koji još nije započeo i prijavljuje pogrešku. |
Rukovatelj završetka grupe
Rukovatelj završetka grupe izvršava se nakon uspješnog ili neuspješnog izvršavanja njenih zadataka. Konačna vrijednost koju grupa prijavljuje ovisi o njezinom Workflow Policy u. Rukovatelj može poduzeti i druge potrebne radnje. Rukovatelj završetka definira se unutar elementa onGroupDone() grupe. Može primati neobavezni argument DoneWith, koji označava uspješno ili neuspješno izvršavanje:
const Group root { onGroupSetup([] { qDebug() << "Postavljanje korijena"; }), QProcessTask(...), onGroupDone([](DoneWith result) { if (result== DoneWith::Success) qDebug() << "Root finished with success"; inače qDebug() << "Root finished with an error"; }) };
Handler grupe je neobavezan. Ako u grupu dodate više od jednog onGroupDone()-a, tijekom izvođenja pokreće se assert koji uključuje poruku o pogrešci.
Napomena: Čak i ako handler za postavljanje grupe vrati StopWithSuccess ili StopWithError, poziva se handler za završetak grupe. Ovo se ponašanje razlikuje od ponašanja handlera za završetak zadatka i može se promijeniti u budućnosti.
Ostali elementi grupe
Grupa može sadržavati i druge elemente koji opisuju tijek obrade, poput načina izvršavanja ili pravila tijeka rada. Također može sadržavati elemente za pohranu koji su odgovorni za prikupljanje i dijeljenje prilagođenih zajedničkih podataka prikupljenih tijekom izvršavanja grupe.
-0000@deepl.internal ili xml-ph-0001@deepl.internal, poziva se rukovatelj događaja grupe. Ovo se ponNačin izvršavanja
Element načina izvršavanja u grupi određuje kako se pokreću izravni podzadaci grupe. Najčešći načini izvršavanja su sequential i parallel. Također je moguće odrediti ograničenje broja zadataka koji se izvršavaju paralelno pomoću funkcije parallelLimit().
U svim načinima izvršavanja grupa pokreće zadatke redoslijedom kojim se pojavljuju.
Ako je podgrupa također grupa, podgrupa pokreće svoje zadatke prema vlastitom načinu izvršavanja.
Pravilo tijeka rada
Element pravila tijeka rada u grupi određuje kako se grupa treba ponašati kada se završi bilo koji zadatak njezina izravnog podređenog člana. Za detaljan opis mogućih pravila pogledajte WorkflowPolicy.
Ako je podgrupa također grupa, podgrupa izvršava svoje zadatke u skladu sa svojom vlastitom politikom tijeka rada.
Pohrana
Koristite element Storage za razmjenu informacija između zadataka. Posebno u načinu sekvencijalne izvedbe, kada zadatak treba podatke iz drugog, već dovršenog zadatka prije nego što može započeti. Na primjer, stablo zadataka koje kopira podatke čitajući ih iz izvora i zapisujući ih na odredište moglo bi izgledati ovako:
statik QByteArray load(const QString&fileName) {... } static void save(const QString&fileName, const QByteArray&array) {... } static Group copyRecipe(const QString&source, const QString&destination) { struct CopyStorage { // [1] prilagođena međuzadaćna struktura QByteArray content; // [2] prilagođeni međuzadaćnipodaci }; // [3] instanca prilagođenog međuzadaćnog struktura kojom upravlja stablo zadataka const Storage<CopyStorage> storage; const auto onLoaderSetup = [source](ConcurrentCall<QByteArray> &async) { async.setConcurrentCallData(&load, source); }; // [4] vrijeme izvršavanja: stablo zadataka aktivira instancu iz [7] prije pozivarukovatelja const auto onLoaderDone = [storage](const ConcurrentCall<QByteArray> &async) { storage->content = async.result(); // [5] učitavač sprema rezultat u pohranu }; // [4] vrijeme izvođenja: stablo zadataka aktivira instancu iz [7] prije pozivanjarukovatelja const auto onSaverSetup = [storage, destination](ConcurrentCall<void> &async) { const QByteArray content = storage->content; // [6] spremač uzima podatke izpohr ane async.setConcurrentCallData(&save, destination, content); }; const auto onSaverDone = [](const ConcurrentCall<void> &async) { qDebug() << "Save done successfully"; }; const Group root { // [7] runtime: stablo zadataka stvara instancu CopyStorage kada se uđe u root storage, ConcurrentCallTask<QByteArray>(onLoaderSetup, onLoaderDone, CallDone::OnSuccess), ConcurrentCallTask<void>(onSaverSetup, onSaverDone, CallDone::OnSuccess) }; return root; } const QString source =...; const QString destination =...; TaskTree taskTree(copyRecipe(source, destination)); connect(&taskTree, &TaskTree::done, &taskTree, [](DoneWith result) { if (result== DoneWith::Success) qDebug() << "The copying finished successfully."; }); tasktree.start();
U gornjem primjeru, podaci između zadataka sastoje se od varijable sadržaja QByteArray [2] obuhvaćene prilagođenom strukturom CopyStorage [1]. Ako se učitavanje uspješno završi, podaci se spremaju u varijablu CopyStorage::content [5]. Spremač zatim koristi tu varijablu za konfiguriranje zadatka spremanja [6].
Kako bi se omogućilo upravljanje strukturom CopyStorage u stablu zadataka, stvara se instanca strukture Storage<CopyStorage> [3]. Ako se kopija ovog objekta umeće kao podređeni element grupe [7], instanca strukture CopyStorage dinamički se stvara kada stablo zadataka uđe u tu grupu. Kada stablo zadataka napusti tu grupu, postojeća instanca strukture CopyStorage uništava se jer više nije potrebna.
Ako se istovremeno pokreće nekoliko stabala zadataka koja drže kopiju zajedničke instance strukture Storage<CopyStorage> (uključujući slučaj kada se stabla zadataka pokreću u različitim nitima), svako stablo zadataka sadrži svoju kopiju strukture CopyStorage.
Možete pristupiti strukturi CopyStorage iz bilo kojeg handler-a u grupi s objektom za pohranu. To uključuje sve handler-e svih potomskih zadataka te grupe. Da biste pristupili prilagođenoj strukturi u handler-u, proslijedite kopiju objekta Storage<CopyStorage> tom handler-u (na primjer, u lambda-zabravi) [4].
Kada stablo zadataka pozove rukovatelja u podstablu koje sadrži spremište [7], stablo zadataka aktivira vlastiti primjerak CopyStorage unutar objekta Storage<CopyStorage>. Stoga se strukturi CopyStorage može pristupiti samo unutar tijela rukovatelja. Za pristup trenutno aktivnom CopyStorage unutar Storage<CopyStorage>, upotrijebite metodu Storage::operator->(), Storage::operator*(), ili Storage::activeStorage().
Sljedeći popis sažima kako upotrijebiti objekt Storage u stablu zadataka:
- Definirajte prilagođenu strukturu
MyStorages prilagođenim podacima [1], [2] - Stvorite instancu pohrane Storage<
MyStorage>[3] - Proslijedite instancu Storage<
MyStorage>u rukovatelje [4] - Pristupite instanci
MyStorageu handlerima [5], [6] - Umetnite instancu Storage<
MyStorage>u grupu [7]
Klasa TaskTree
TaskTree izvršava stablo asinkronih zadataka prema receptu opisanom od strane korijenskog elementa grupe.
Budući da je TaskTree također asinhroni zadatak, može biti dio drugog TaskTree-a. Da biste smjestili ugniježđeni TaskTree unutar drugog TaskTree-a, umetnite element TaskTreeTask u drugi element Group.
TaskTree tijekom izvođenja izvještava o napretku dovršenih zadataka. Vrijednost napretka povećava se kada se zadatak završi ili preskoči ili otkaže. Kada je TaskTree dovršen i emitira se signal TaskTree::done(), trenutna vrijednost napretka jednaka je maksimalnoj vrijednosti napretka. Maksimalni napredak jednak je ukupnom broju asinkronih zadataka u stablu. Ugniježđeni TaskTree računa se kao jedan zadatak, a njegovi podređeni zadaci se ne računaju u stablu najviše razine. Grupe same po sebi se ne računaju kao zadaci, ali se računaju njihovi zadaci. Zadaci grupe ' Sync ' nisu asinkroni, stoga se ne računaju kao zadaci.
Za postavljanje dodatnih početnih podataka za aktivno stablo, izmijenite instance pohrane u stablu prilikom njihova stvaranja instaliranjem rukovatelja za postavljanje pohrane:
Storage<CopyStorage> storage; const Group root = ...; // storage placed inside root's group and inside handlers TaskTree taskTree(root); auto initStorage = [](CopyStorage &storage) { storage.content = "initial content"; }; taskTree.onStorageSetup(storage, initStorage); taskTree.start();
Kada stablo zadataka u tijeku stvori instancu CopyStorage i prije nego što se pozove bilo koji handler unutar stabla, stablo zadataka poziva handler initStorage kako bi omogućilo postavljanje početnih podataka pohrane, jedinstvenih za ovo posebno izvođenje taskTree-a.
Slično tome, za prikupljanje dodatnih rezultatskih podataka iz aktivnog stabla, pročitajte ih iz instanci pohrane u stablu kada se one spremaju uništiti. Da biste to učinili, instalirajte rukovatelja za završetak pohrane (storage done handler):
Storage<CopyStorage> storage; const Group root =...; // spremište postavljeno unutar root grupe i unutarhandlera TaskTree taskTree(root); auto collectStorage = [](const CopyStorage &storage) { qDebug() << "final content" << storage.content; }; taskTree.onStorageDone(storage, collectStorage); taskTree.start();
Kada se pokretno stablo zadataka sprema uništiti instancu spremnika ( CopyStorage ), stablo zadataka poziva rukovatelj collectStorage kako bi omogućilo čitanje konačnih podataka iz spremnika, jedinstvenih za ovu konkretnu izvedbu taskTree-a.
Prilagodnici zadataka
Za proširenje TaskTree-a novom vrstom zadatka implementirajte jednostavnu adapter klasu naslijeđenu od predloška klase TaskAdapter. Sljedeća klasa je adapter za jednokratni tajmer, koji se može smatrati novim asinkronim zadatkom:
class TimerTaskAdapter : public TaskAdapter<QTimer> { public: TimerTaskAdapter() { task()->setSingleShot(true); task()->setInterval(1000); connect(task(), &QTimer::timeout, this, [this] { emit done(DoneResult::Success); }); } private: void start() final { task()->start(); } }; using TimerTask = CustomTask<TimerTaskAdapter>;
Prilagođeni adapter morate naslijediti od predloška klase TaskAdapter instanciranog s predloškom parametra klase koja implementira zadatak u tijeku. Gornji kôd koristi QTimer za pokretanje zadatka. Ta se klasa kasnije pojavljuje kao argument rukovateljima zadatka. Instanca ovog parametra klase automatski postaje član predloška TaskAdapter i dostupna je putem metode TaskAdapter::task(). Konstruktor klase TimerTaskAdapter početno konfigurira objekt QTimer i povezuje se sa signalom QTimer::timeout() (signal za prekid). Kada se signal aktivira, klasa TimerTaskAdapter emitira signal TaskInterface::done(DoneResult::Success) kako bi obavijestila stablo zadataka da je zadatak uspješno završen. Ako emitira signal TaskInterface::done(DoneResult::Error), zadatak je završen s greškom. Metoda TaskAdapter::start() pokreće tajmer.
Da bi QTimer bio dostupan unutar TaskTree-a pod imenom TimerTask, definirajte TimerTask kao alias za CustomTask<TimerTaskAdapter>. TimerTask postaje novi prilagođeni tip zadatka, koristeći TimerTaskAdapter.
Nova vrsta zadatka je sada registrirana i možete je koristiti u TaskTree:
const auto onSetup = [](QTimer &task) { task.setInterval(2000); }; const auto onDone = [] { qDebug() << "timer triggered"; }; const Group root { TimerTask(onSetup, onDone) };
Kada se pokrene stablo zadataka koje sadrži korijen iz gornjeg primjera, ispisuje se poruka za otklanjanje pogrešaka unutar dvije sekunde, a zatim se uspješno završava.
Napomena: klasa koja implementira pokrenutu zadatak mora imati zadani konstruktor, a objekti te klase moraju biti slobodno uništivi. Trebalo bi biti dopušteno uništiti pokrenuti objekt, po mogućnosti bez čekanja da se pokrenuti zadatak završi (tj. siguran neblokirajući uništitelj pokrenutog zadatka). Da biste postigli neblokirajuće uništenje zadatka koji ima blokirajući uništitelj, razmislite o korištenju opcionalnog parametra predloška Deleter kod TaskAdaptera.
Dokumentacija članovskih funkcija
TaskTree::TaskTree(QObject *parent = nullptr)
Izrađuje prazno stablo zadataka. Koristite setRecipe() za prosljeđivanje deklarativnog opisa načina na koji stablo zadataka treba izvršavati zadatke i kako treba rukovati dovršenim zadacima.
Pokretanje praznog stabla zadataka je bez učinka i prikazuje se odgovarajuća upozoravajuća poruka.
Vidi također setRecipe() i start().
TaskTree::TaskTree(const Tasking::Group &recipe, QObject *parent = nullptr)
Konstruira stablo zadataka s danim recipe om. Nakon što se stablo zadataka pokrene, izvršava zadatke sadržane u recipe u i obrađuje dovršene zadatke prema proslijeđenom opisu.
Ovo je preopterećena funkcija.
Vidi također setRecipe() i start().
[virtual noexcept] TaskTree::~TaskTree()
Uništava stablo zadataka.
Kada se stablo zadataka izvršava dok se uništava, odmah otkazuje sve tekuće zadatke. U tom slučaju ne pozivaju se nikakvi rukovatelji, pa čak ni rukovatelji grupa i zadataka za završetak niti rukovatelji za prekid zadataka ( onStorageDone()). Stablo zadataka također ne emitira nikakve signale iz destruktora, pa čak ni signale done() ili progressValueChanged(). Na ovo se ponašanje uvijek može osloniti. Potpuno je sigurno uništiti stablo zadataka koje je u tijeku.
Uobičajena je praksa uništavati stablo zadataka koje se izvršava. Jamčeno je da će se uništenje izvršiti brzo, bez potrebe za čekanjem da trenutno izvršavajući zadaci završe, pod uvjetom da zadaci koji se koriste implementiraju svoje destruktore na neblokirajući način.
Napomena: Ne pozivajte direktno destruktor ni iz kojeg od upravljača pokrenutih zadataka niti s signala stabla zadataka. U tim slučajevima koristite deleteLater() umjesto toga.
Vidi također cancel().
int TaskTree::asyncCount() const
Vraća trenutni stvarni broj asinkronih lanaca poziva.
Vraćena vrijednost označava koliko se puta kontrola vraća u petlju događaja pozivatelja dok stablo zadataka radi. Početno je ova vrijednost 0. Ako izvršavanje stabla zadataka završi potpuno sinkrono, ova vrijednost ostaje 0. Ako stablo zadataka sadrži bilo koje asinkrone zadatke koji su uspješno pokrenuti tijekom poziva start(), ova se vrijednost povećava na 1 neposredno prije završetka poziva start(). Kasnije, kada se bilo koji asinkroni zadatak završi i pokrenu se svi mogući nastavci, vrijednost se ponovno povećava. Povećavanje se nastavlja sve dok se stablo zadataka ne završi. Kada stablo zadataka emitira signal done(), povećavanje se zaustavlja. Signal asyncCountChanged() emitira se pri svakom povećanju ove vrijednosti.
Vidi također asyncCountChanged().
[signal] void TaskTree::asyncCountChanged(int count)
Ovaj signal se emitira kada je stablo zadataka u tijeku izvršavanja spremno vratiti kontrolu pozivateljevoj petlji događaja. Kada se stablo zadataka pokrene, ovaj se signal emitira s vrijednošću count od 0, a kasnije se emitira pri svakom porastu vrijednosti asyncCount() uz ažuriranu vrijednost count. Svaki poslan signal (osim početnog s vrijednošću 0) jamči da stablo zadataka i dalje radi asinkrono nakon emitiranja.
Vidi također asyncCount().
void TaskTree::cancel()
Otkazuje izvršavanje stabla aktivnih zadataka.
Odmah otkazuje sve aktivne zadatke. Svi aktivni zadaci završavaju s greškom, pozivajući svoje rukovatelje grešaka. Sve aktivne grupe raspoređuju svoje rukovatelje prema pravilima tijeka rada, pozivajući svoje rukovatelje za završetak. Također se pozivaju rukovatelji onStorageDone() pohrana. Signali progressValueChanged() također se šalju. Na ovo se ponašanje uvijek može osloniti.
Funkcija cancel() izvršava se sinkrono, tako da nakon poziva cancel() svi aktivni zadaci završavaju i stablo je već otkazano. Jamčeno je da će cancel() raditi brzo, bez blokirajućeg čekanja da trenutno aktivni zadaci završe, pod uvjetom da zadaci koji se koriste implementiraju svoje destruktore na neblokirajući način.
Kada je stablo zadataka prazno, tj. konstruirano s podrazumijevanim konstruktom, poziv cancel() je bez učinka (no-op) i prikazuje se odgovarajuća upozoravajuća poruka.
U suprotnom, kada stablo zadataka nije pokrenuto, poziv cancel() se zanemaruje.
Napomena: Ne pozivajte ovu funkciju izravno iz bilo kojeg rukovatelja pokrenute zadatke ili signala stabla zadataka.
Vidi također ~TaskTree().
[signal] void TaskTree::done(Tasking::DoneWith result)
Ovaj signal se emitira kada je stablo zadataka dovršeno, prosljeđujući konačni result izvršenja. Stablo zadataka nakon emitiranja ovog signala ni ne poziva nijedan rukovatelj, ni ne emitira nijedan signal.
Napomena: Nemojte brisati stablo zadataka izravno u rukovatelju ovog signala. Umjesto toga upotrijebite deleteLater()
Vidi također started().
bool TaskTree::isRunning() const
Vraća true ako se stablo zadataka trenutno izvršava; inače vraća false.
Vidi također start() i cancel().
template <typename StorageStruct, typename Handler> void TaskTree::onStorageDone(const Tasking::Storage<StorageStruct> &storage, Handler &&handler)
Instalira spremnik dovršen handler a za storage kako bi dinamički preuzeo konačne podatke iz aktivnog stabla zadataka.
StorageHandler uzima referencu const na instancu StorageStruct:
statik QByteArray load(const QString&fileName) {... } Storage<QByteArray> storage; const auto onLoaderSetup = [](ConcurrentCall<QByteArray> &concurrent) { concurrent.setConcurrentCallData(&load, "foo.txt"); }; const auto onLoaderDone = [storage](const ConcurrentCall<> &concurrent) { concurrent.setConcurrentCallData(&load, "foo.txt"); }; const Group root { storage, ConcurrentCallTask(onLoaderSetup , onLoaderDone, CallDone::QByteArray> &concurrent) { *storage = concurrent.result(); }; const Group root { storage, ConcurrentCallTask(onLoaderSetup, onLoaderDone, CallDone::OnSuccess) }; TaskTree taskTree(root); auto collectStorage = [](const QByteArray&storage){ qDebug() << "final content" << storage; taskTree.onStorageDone(storage, collectStorage); taskTree.start();
Kada je aktivno stablo zadataka spremno napustiti Grupu u kojoj je smješten storage, uništava instancu StorageStruct. Neposredno prije uništenja instance StorageStruct i nakon što su pozvani svi mogući rukovatelji iz ove grupe, stablo zadataka poziva proslijeđeni handler. To omogućuje dinamičko čitanje konačnog sadržaja danog spremišta i njegovu daljnju obradu izvan stabla zadataka.
Ovaj se rukovatelj također poziva kada se aktivno stablo otkaže. Međutim, ne poziva se kada se aktivno stablo uništi.
Vidi također onStorageSetup().
template <typename StorageStruct, typename Handler> void TaskTree::onStorageSetup(const Tasking::Storage<StorageStruct> &storage, Handler &&handler)
Instalira konfiguraciju pohrane handler koja omogućuje storage u da dinamički proslijedi početne podatke stablu aktivnih zadataka.
StorageHandler uzima referencu na instancu StorageStruct:
static void save(const QString &fileName, const QByteArray &array) { ... } Storage<QByteArray> storage; const auto onSaverSetup = [storage](ConcurrentCall<QByteArray> &concurrent) { concurrent.setConcurrentCallData(&save, "foo.txt", *storage); }; const Group root { storage, ConcurrentCallTask(onSaverSetup) }; TaskTree taskTree(root); auto initStorage = [](QByteArray &storage){ storage = "initial content"; }; taskTree.onStorageSetup(storage, initStorage); taskTree.start();
Kada aktivno stablo zadataka uđe u grupu u kojoj je smještena storage, stvara instancu StorageStruct spremnu za korištenje unutar te grupe. Odmah nakon stvaranja instance StorageStruct, i prije poziva bilo kojeg handler-a ove grupe, stablo zadataka poziva proslijeđeni handler. To omogućuje dinamičko postavljanje početnog sadržaja za zadano spremište. Kasnije, kada se pozove handler neke grupe, stablo zadataka aktivira stvoreno i inicijalizirano spremište, tako da je dostupno unutar handler-a bilo koje grupe.
Vidi također onStorageDone().
int TaskTree::progressMaximum() const
Vraća maksimalni progressValue().
Napomena: Trenutno je isto kao taskCount(). To bi se moglo promijeniti u budućnosti.
Vidi također progressValue().
int TaskTree::progressValue() const
Vraća trenutnu vrijednost napretka, koja se nalazi između 0 i progressMaximum().
Vraćeni broj označava koliko je zadataka već dovršeno, otkazano ili preskočeno tijekom izvođenja stabla zadataka. Kada se stablo zadataka pokrene, taj je broj postavljen na 0. Kada se stablo zadataka završi, taj broj uvijek iznosi progressMaximum().
Vidi također progressMaximum() i progressValueChanged().
[signal] void TaskTree::progressValueChanged(int value)
Ovaj signal se emitira kada je stablo zadataka u tijeku dovršilo, otkazalo ili preskočilo neke zadatke. Signal value daje trenutni ukupan broj dovršenih, otkazanih ili preskočenih zadataka. Kada se stablo zadataka pokrene i nakon što je emitiran signal started(), ovaj se signal emitira s početnim value od 0. Kada je stablo zadataka pri završetku i prije nego što se emitira signal done(), ovaj se signal emitira s konačnim value od progressMaximum().
Vidi također progressValue() i progressMaximum().
Tasking::DoneWith TaskTree::runBlocking()
Pokreće lokalnu petlju događaja s parametrima QEventLoop::ExcludeUserInputEvents i pokreće stablo zadataka.
Vraća DoneWith::Success ako je stablo zadataka uspješno završeno; inače vraća DoneWith::Error.
Napomena: Izbjegavajte korištenje ove metode iz glavne niti. Umjesto toga koristite asinkronu metodu start() . Ova se metoda koristi u pozadinskim nitima ili u automatskim testovima.
Vidi također start().
[static] Tasking::DoneWith TaskTree::runBlocking(const Tasking::Group &recipe)
Konstruira privremeno stablo zadataka koristeći proslijeđeni recipe i pokreće ga blokirajuće.
Vraća DoneWith::Success ako je stablo zadataka uspješno završeno; inače vraća DoneWith::Error.
Napomena: Izbjegavajte korištenje ove metode u glavnoj niti. Umjesto toga upotrijebite asinkronu metodu start() . Ova se metoda koristi u pozadinskim nitima ili u automatiziranim testovima.
Vidi također start().
Tasking::DoneWith TaskTree::runBlocking(const QFuture<void> &future)
Prosljeđeni future služi za slušanje događaja otkazivanja. Kada se stablo zadataka otkaže, ova metoda otkazuje proslijeđeni future.
Ova funkcija preopterećuje TaskTree::runBlocking().
[static] Tasking::DoneWith TaskTree::runBlocking(const Tasking::Group &recipe, const QFuture<void> &future)
Prosljeđeni future koristi se za slušanje događaja otkazivanja. Kada se stablo zadataka otkaže, ova metoda otkazuje proslijeđeni future.
Ova funkcija preopterećuje TaskTree::runBlocking(const Group &recipe).
void TaskTree::setRecipe(const Tasking::Group &recipe)
Postavlja zadanu recipe za stablo zadataka. Nakon što se stablo zadataka pokrene, izvršava zadatke sadržane u recipe i obrađuje dovršene zadatke prema proslijeđenom opisu.
Napomena: Ako se pozove za aktivno stablo zadataka, poziv se zanemaruje.
Vidi također TaskTree (const Tasking::Group &recipe) i start().
void TaskTree::start()
Pokreće stablo zadataka.
Koristite setRecipe() ili konstruktor za postavljanje deklarativnog opisa prema kojem će stablo zadataka izvršavati sadržane zadatke i obrađivati dovršene zadatke.
Kada je stablo zadataka prazno, tj. konstruirano s podrazumijevanim konstruktorom, poziv start() je bez učinka i prikazuje se odgovarajuća poruka upozorenja.
U suprotnom, kada je stablo zadataka već pokrenuto, poziv start() se zanemaruje i prikazuje se odgovarajuća poruka upozorenja.
U suprotnom se stablo zadataka pokreće.
Pokrenuto stablo zadataka može završiti sinkrono, na primjer kada handler za početak glavne grupe vrati SetupResult::StopWithError. Iz tog razloga, veza na signal done treba uspostaviti prije poziva start(). Koristite isRunning() kako biste otkrili je li stablo zadataka još uvijek aktivno nakon poziva start().
Implementacija stabla zadataka oslanja se na aktivnu petlju događaja. Pobrinite se da je metoda QEventLoop, QCoreApplication ili neka od njenih podklasa pokrenuta (ili da će biti pokrenuta) kada pozivate ovu metodu.
Vidi također TaskTree (const Tasking::Group &), setRecipe(), isRunning(), i cancel().
[signal] void TaskTree::started()
Ovaj signal se emitira kada se pokrene stablo zadataka. Emitiranje ovog signala sinkrono slijedi signal progressValueChanged() s početnom vrijednošću 0.
Vidi također start() i done().
int TaskTree::taskCount() const
Vraća broj asinkronih zadataka sadržanih u spremljenoj recepturi.
Sync Napomena: Vraćeni broj ne uključuje zadatke s vremenskim ograničenjem.
Napomena: Svaki zadatak ili grupa postavljen pomoću withTimeout() povećava ukupan broj zadataka za 1.
Vidi također setRecipe() i progressMaximum().
Copyright © The Qt Company Ltd. and other contributors. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.