Anulowanie w PPL
W tym dokumencie omówiono rolę anulowania w równoległych Biblioteka wzorców (PPL), jak anulować równoległą pracę i sposobu ustalania, kiedy praca zostanie anulowane.
[!UWAGA]
Środowisko wykonawcze używa obsługi wyjątków do zaimplementowania anulowania.Nie złapać lub obsługę tych wyjątków w kodzie.Ponadto zaleca się napisać kod zarządzany wyjątek w organach funkcja dla zadań.Na przykład, można użyć Inicjowania jest przejęcie zasobu (RAII) wzorcem w celu zapewnienia, że zasoby są obsługiwane poprawnie gdy wyjątek w treści zadania.Na przykład pełne oczyszczanie zasobu w zadaniu cancelable przy użyciu wzoru RAII, zobacz Wskazówki: usuwanie pracy z wątku interfejs użytkownika.
Kwestie kluczowe
Anulowanie jest wspólne i wymaga koordynacji między kodem, który żąda unieważnienia i zadań, który odpowiada na anulowanie.
Jeśli to możliwe, można użyć tokeny odwołania do anulowania pracy.Concurrency::cancellation_token klasa definiuje token odwołania.
Po użyciu tokenów odwołania za pomocą concurrency::cancellation_token_source::cancel metodą inicjowania anulowania i concurrency::is_task_cancellation_requested i concurrency::cancel_current_task funkcje odpowiada na anulowanie.
Anulowanie nie następuje natychmiast.Chociaż nowa praca nie jest uruchomiona, jeśli zadania lub grupy zadań zostanie anulowana, aktywnej pracy musi sprawdzić i odpowiadanie na anulowanie.
Kontynuacja oparte na wartościach dziedziczy token odwołania antecedent zadań.Kontynuacja opartego na zadaniach nigdy nie dziedziczy token swoje zadania antecedent.
Użycie concurrency::cancellation_token:: Brak metoda podczas wywołania konstruktora lub funkcję, która przyjmuje cancellation_token obiektu, ale nie powinien być anulowanie operacji.Ponadto jeśli nie przechodzą token odwołania do concurrency::task Konstruktor lub concurrency::create_task funkcji, to zadanie nie jest anulowanie.
W tym dokumencie
Równoległe drzewka pracy
Anulowanie zadań równoległych
Korzystając z tokena odwołania, aby anulować czynność równoległą
Korzystając z metody odwołania, aby anulować czynność równoległą
Korzystając z wyjątków, aby anulować czynność równoległą
Anulowanie algorytmów równoległych
Kiedy nie należy używać odwołania
Równoległe drzewka pracy
PPL używa zadań i grup zadań zarządzania zadaniami szczegółowymi zasadami i obliczeń.Można zagnieździć grup zadań do formularza drzew pracy równolegle.Na poniższej ilustracji przedstawiono drzewa równoległą pracę.Na tej ilustracji tg1 i tg2 reprezentują grupy zadań; t1, t2, t3, t4, i t5 reprezentują pracy, które wykonują grupy zadań.
Poniższy przykład zawiera kod, który jest wymagany do tworzenia drzewa na ilustracji.W tym przykładzie tg1 i tg2 są concurrency::structured_task_group przedmiotami; t1, t2, t3, t4, and t5 are concurrency::task_handle objects.
// task-tree.cpp
// compile with: /c /EHsc
#include <ppl.h>
#include <sstream>
#include <iostream>
#include <sstream>
using namespace concurrency;
using namespace std;
void create_task_tree()
{
// Create a task group that serves as the root of the tree.
structured_task_group tg1;
// Create a task that contains a nested task group.
auto t1 = make_task([&] {
structured_task_group tg2;
// Create a child task.
auto t4 = make_task([&] {
// TODO: Perform work here.
});
// Create a child task.
auto t5 = make_task([&] {
// TODO: Perform work here.
});
// Run the child tasks and wait for them to finish.
tg2.run(t4);
tg2.run(t5);
tg2.wait();
});
// Create a child task.
auto t2 = make_task([&] {
// TODO: Perform work here.
});
// Create a child task.
auto t3 = make_task([&] {
// TODO: Perform work here.
});
// Run the child tasks and wait for them to finish.
tg1.run(t1);
tg1.run(t2);
tg1.run(t3);
tg1.wait();
}
Można również użyć concurrency::task_group klasy, aby utworzyć podobne drzewo pracy.Concurrency::task klasa obsługuje również pojęcie drzewa pracy.Jednakże task drzewa jest drzewo zależności.W task drzewo, przyszłych prac zakończy się po bieżącej pracy.W drzewie grupy zadań wewnętrzne gniazdo kończy się przed zewnętrznej pracy.Aby uzyskać więcej informacji na temat różnic między zadaniami i grup zadań, zobacz Równoległość zadania (współbieżność środowiska wykonawczego).
[U góry]
Anulowanie zadań równoległych
Istnieje wiele sposobów Aby anulować równoległą pracę.Preferowanym sposobem jest użycie tokenu odwołania.Grupy zadań również wsparcie concurrency::task_group::cancel metody i concurrency::structured_task_group::cancel metody.Ostatnim sposobem jest wyjątek w treści funkcji pracy zadania.Niezależnie od wybranej metody zrozumieć, że unieważnienie nie występuje natychmiast.Chociaż nowa praca nie jest uruchomiona, jeśli zadania lub grupy zadań zostanie anulowana, aktywnej pracy musi sprawdzić i odpowiadanie na anulowanie.
Aby uzyskać więcej przykładów, które anulowanie zadań równoległych, zobacz Wskazówki: Łączenie za pomocą zadań i żądań XML HTTP, Porady: użyj anulowania, aby przerwać pętlę równoległą, i Porady: Użyj obsługi wyjątków, aby przerwać pętlę równoległą.
Korzystając z tokena odwołania, aby anulować czynność równoległą
task, task_group, I structured_task_group klas obsługuje anulowania przy użyciu tokenów anulowania.Definiuje PPL concurrency::cancellation_token_source i concurrency::cancellation_token klas w tym celu.Korzystając z tokenu odwołania do anulowania pracy, środowiska wykonawczego nie można uruchomić nowej pracy, że zgadza się token.Pracy, która jest już aktywny można monitorować jego token odwołania i Zatrzymaj, gdy to może.
Aby zainicjować anulowania, wywołanie concurrency::cancellation_token_source::cancel metody.Użytkownik odpowiada na anulowanie w następujący sposób:
Dla task obiekty, użyj concurrency::is_task_cancellation_requested i concurrency::cancel_current_task funkcji.cancel_current_taskAnulowanie bieżącego zadania oraz wszystkie jego kontynuacji oparte na wartościach. (Nie powoduje anulowania anulowanie token skojarzonego z zadaniem lub jego kontynuacji.)
Dla grup zadań i algorytmy równoległe, użyj concurrency::is_current_task_group_canceling funkcja wykrywania anulowania i jak najszybciej powrócić z treści zadania, gdy ta funkcja zwraca true. (Nie wymagają cancel_current_task z grupy zadań.)
Poniższy przykład pokazuje pierwszy podstawowy wzorzec dla zadania anulowania.Treści zadania sprawdza od czasu do czasu unieważnienia wewnątrz pętli.
// task-basic-cancellation.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>
#include <sstream>
using namespace concurrency;
using namespace std;
bool do_work()
{
// Simulate work.
wcout << L"Performing work..." << endl;
wait(250);
return true;
}
int wmain()
{
cancellation_token_source cts;
auto token = cts.get_token();
wcout << L"Creating task..." << endl;
// Create a task that performs work until it is canceled.
auto t = create_task([]
{
bool moreToDo = true;
while (moreToDo)
{
// Check for cancellation.
if (is_task_cancellation_requested())
{
// TODO: Perform any necessary cleanup here...
// Cancel the current task.
cancel_current_task();
}
else
{
// Perform work.
moreToDo = do_work();
}
}
}, token);
// Wait for one second and then cancel the task.
wait(1000);
wcout << L"Canceling task..." << endl;
cts.cancel();
// Wait for the task to cancel.
wcout << L"Waiting for task to complete..." << endl;
t.wait();
wcout << L"Done." << endl;
}
/* Sample output:
Creating task...
Performing work...
Performing work...
Performing work...
Performing work...
Canceling task...
Waiting for task to complete...
Done.
*/
cancel_current_task Funkcja rzutów; w związku z tym nie trzeba jawnie powrócić z bieżącej pętli lub funkcji.
Porada |
---|
Alternatywnie, można wywołać concurrency::interruption_point działać zamiast is_task_cancellation_requested i cancel_current_task. |
Ważne jest, aby wywołać cancel_current_task kiedy możesz odpowiedzieć na anulowanie, ponieważ przejścia zadanie do stanu Anulowano.Jeśli powrócisz początku zamiast telefonicznej cancel_current_task, operacja przejścia do stanu wykonanego i wszelkie kontynuacji oparte na wartościach są uruchamiane.
Przestroga |
---|
Nigdy nie rzucać task_canceled w kodzie.Zamiast tego wywołaj metodę cancel_current_task. |
Gdy zadanie kończy się w stanie anulowane, concurrency::task::get wyrzuca metoda concurrency::task_canceled. (Z drugiej strony, concurrency::task::wait zwraca task_status::canceled i nie rzuca.) Poniższy przykład ilustruje to zachowanie dla utrzymania zorientowane zadaniowo.Kontynuacja opartego na zadaniach zawsze nazywa się, nawet wtedy, gdy zadanie antecedent jest anulowane.
// task-canceled.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
auto t1 = create_task([]() -> int
{
// Cancel the task.
cancel_current_task();
});
// Create a continuation that retrieves the value from the previous.
auto t2 = t1.then([](task<int> t)
{
try
{
int n = t.get();
wcout << L"The previous task returned " << n << L'.' << endl;
}
catch (const task_canceled& e)
{
wcout << L"The previous task was canceled." << endl;
}
});
// Wait for all tasks to complete.
t2.wait();
}
/* Output:
The previous task was canceled.
*/
Ponieważ oparte na wartościach kontynuacji dziedziczą token ich antecedent zadań, chyba że zostały utworzone z tokenem jawne, kontynuacji natychmiast wprowadzić stan Anulowane, nawet wtedy, gdy antecedent zadanie jest nadal wykonywane.W związku z tym każdy wyjątek, który jest generowany przez antecedent zadanie po anulowaniu nie są propagowane do zadań kontynuacji.Anulowanie zawsze zastępuje stan zadania antecedent.Poniższy przykład przypomina poprzedni, ale przedstawia zachowanie dla utrzymania oparte na wartościach.
auto t1 = create_task([]() -> int
{
// Cancel the task.
cancel_current_task();
});
// Create a continuation that retrieves the value from the previous.
auto t2 = t1.then([](int n)
{
wcout << L"The previous task returned " << n << L'.' << endl;
});
try
{
// Wait for all tasks to complete.
t2.get();
}
catch (const task_canceled& e)
{
wcout << L"The task was canceled." << endl;
}
/* Output:
The task was canceled.
*/
Przestroga |
---|
Jeśli nie przechodzą token odwołania do task Konstruktor lub concurrency::create_task funkcji, to zadanie nie jest anulowanie.Ponadto musi przejść do tego samego tokenu odwołania do konstruktora żadnych zadań zagnieżdżonych (to znaczy zadania, które są tworzone w treści innego zadania) aby anulować wszystkie zadania jednocześnie. |
Możesz chcieć uruchomienie dowolnego kodu po anulowaniu token odwołania.Na przykład, jeśli Twój użytkownik zdecyduje, że Anulowanie przycisk w interfejsie użytkownika, aby anulować operację, można wyłączyć tego przycisku, dopóki użytkownik nie uruchomi innej operacji.Poniższy przykład pokazuje, jak używać concurrency::cancellation_token::register_callback metoda zarejestrować funkcja wywołania zwrotnego, wykonywana przy token anulowanie zostało anulowane.
// task-cancellation-callback.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>
using namespace concurrency;
using namespace std;
int wmain()
{
cancellation_token_source cts;
auto token = cts.get_token();
// An event that is set in the cancellation callback.
event e;
cancellation_token_registration cookie;
cookie = token.register_callback([&e, token, &cookie]()
{
wcout << L"In cancellation callback..." << endl;
e.set();
// Although not required, demonstrate how to unregister
// the callback.
token.deregister_callback(cookie);
});
wcout << L"Creating task..." << endl;
// Create a task that waits to be canceled.
auto t = create_task([&e]
{
e.wait();
}, token);
// Cancel the task.
wcout << L"Canceling task..." << endl;
cts.cancel();
// Wait for the task to cancel.
t.wait();
wcout << L"Done." << endl;
}
/* Sample output:
Creating task...
Canceling task...
In cancellation callback...
Done.
*/
Dokument Równoległość zadania (współbieżność środowiska wykonawczego) wyjaśnienie różnic pomiędzy kontynuacji oparte na wartościach i zorientowane zadaniowo.Jeśli nie podasz cancellation_token obiekt z zadaniem kontynuacji kontynuacji dziedziczy token odwołania antecedent zadanie w następujący sposób:
Oparte na wartościach kontynuacja zawsze dziedziczy token odwołania antecedent zadania.
Kontynuacja opartego na zadaniach nigdy nie dziedziczy token odwołania antecedent zadania.Jedynym sposobem, aby uczynić cancelable kontynuacji opartego na zadaniach jest jawnie przekazanie token odwołania.
Takie zachowanie nie dotyczy błędowi zadania (to jest taką, która zgłasza wyjątek).W tym przypadku odwołania oparte na wartościach utrzymania; kontynuacja opartego na zadaniach nie został anulowany.
Przestroga |
---|
Zadanie, które jest tworzona w innym zadaniem (innymi słowy, zadanie zagnieżdżonych) nie dziedziczą token anulowanie zadania nadrzędnego.Tylko kontynuacja oparte na wartościach dziedziczy token odwołania antecedent zadań. |
Porada |
---|
Użycie concurrency::cancellation_token:: Brak metoda podczas wywołania konstruktora lub funkcję, która przyjmuje cancellation_token obiektu i nie powinien być anulowanie operacji. |
Możesz także podać token odwołania do konstruktora task_group lub structured_task_group obiektu.Ważnym aspektem tego jest, że grupy zadań podrzędnych dziedziczą token ten anulowania.Na przykład demonstrujący tego pojęcia za pomocą concurrency::run_with_cancellation_token funkcji uruchamianie do wywoływania parallel_for, zobacz Algorytmy równoległe anulowanie później w tym dokumencie.
[U góry]
Anulowanie tokenów i kompozycji zadania
Concurrency::when_all i concurrency::when_any funkcje mogą pomóc komponować wiele zadań do wykonania typowe wzorce.W tej sekcji opisano, jak działają te funkcje z tokenów anulowania.
Kiedy dostarczasz token odwołania do jednej when_all i when_any funkcjonować, że funkcja anuluje tylko wtedy, gdy token anulowania rezerwacji zostanie anulowana lub gdy jeden uczestnik zadań kończy się w stan Anulowane lub zgłasza wyjątek.
when_all Funkcja dziedziczy token odwołania każdego zadania, który redaguje całokształtu funkcjonowania, jeśli nie podasz token odwołania do niego.Zadania, które są zwracane z when_all została anulowana podczas żadnego z tych tokenów są anulowane i co najmniej jeden uczestnik zadań nie została jeszcze uruchomiona lub jest uruchomiona.Podobne zachowanie występuje, gdy jedno z zadań zgłasza wyjątek — zadania, który jest zwracany z when_all natychmiast zostanie anulowana z tego wyjątku.
Środowisko wykonawcze wybiera token anulowanie zadania, który jest zwracany z when_any działać po zakończeniu tego zadania.Jeśli żaden z uczestników zadania Zakończ w stan wykonany i zgłasza wyjątek, jeden lub więcej zadań, wybierany jest jednym z zadań, które zgłosił do ukończenia when_any i jego token został wybrany jako tokenem ostatnim zadaniem.Jeżeli więcej niż jedno zadanie kończy się w wypełniony podać, zadania, który jest zwracany z when_any zadanie kończy się w stan wykonany.Środowisko wykonawcze próbuje odebrać zakończone zadanie, którego token nie zostało anulowane w chwili zakończenia tak, że zadanie jest zwracane z when_any nie jest natychmiast anulowane, nawet jeśli inne wykonującym zadania może zostać ukończone w dowolnym momencie.
[U góry]
Korzystając z metody odwołania, aby anulować czynność równoległą
Concurrency::task_group::cancel i concurrency::structured_task_group::cancel metody ustawić grupę zadań stan anulowane.Po wywołaniu cancel, grupy zadań nie można uruchomić zadania przyszłe.cancel Metody może być wywoływana przez wiele zadań podrzędnych.Anulowane zadania powoduje concurrency::task_group::wait i concurrency::structured_task_group::wait metody zwracały concurrency::canceled.
Jeśli grupa zadań została anulowana, wywołania z każdego zadania podrzędnego w czasie wykonywania może wywołać punkt przerwania, co powoduje, że runtime do zgłaszanie i wychwytywanie typu wewnętrzny wyjątek, aby anulować zadania aktywne.W czasie wykonywania współbieżność nie definiuje punktów przerwania szczególne; może ona występować wywołania dowolnej środowiska wykonawczego.Środowisko wykonawcze muszą obsługiwać wyjątków, które to wyrzuca w celu wykonania anulowania.W związku z tym obsługują nieznany wyjątki w treści zadania.
Jeśli zadania podrzędne wykonuje operację czasochłonne i nie wymaga się w czasie wykonywania, musi okresowo sprawdzaj anulowania i zakończyć pracę w sposób terminowy.Poniższy przykład przedstawia sposób do określenia, kiedy praca zostanie anulowane.Zadanie t4 anuluje nadrzędna grupa zadań po napotkaniu błędu.Zadanie t5 od czasu do czasu wywołania structured_task_group::is_canceling , aby sprawdzić, do anulowania.W przypadku anulowania nadrzędna grupa zadań zadań t5 odpowiedni komunikat i kończy pracę.
structured_task_group tg2;
// Create a child task.
auto t4 = make_task([&] {
// Perform work in a loop.
for (int i = 0; i < 1000; ++i)
{
// Call a function to perform work.
// If the work function fails, cancel the parent task
// and break from the loop.
bool succeeded = work(i);
if (!succeeded)
{
tg2.cancel();
break;
}
}
});
// Create a child task.
auto t5 = make_task([&] {
// Perform work in a loop.
for (int i = 0; i < 1000; ++i)
{
// To reduce overhead, occasionally check for
// cancelation.
if ((i%100) == 0)
{
if (tg2.is_canceling())
{
wcout << L"The task was canceled." << endl;
break;
}
}
// TODO: Perform work here.
}
});
// Run the child tasks and wait for them to finish.
tg2.run(t4);
tg2.run(t5);
tg2.wait();
W tym przykładzie sprawdza odwołania na każde 100th iteracji pętli zadania.Ilość pracy, którą wykonuje swoje zadania i jak szybko potrzebne dla zadań odpowiada na anulowanie zależy od częstotliwości, z jaką Sprawdź do anulowania.
Jeśli nie masz dostępu do obiektu nadrzędnego grupy zadań, wywołanie concurrency::is_current_task_group_canceling funkcja, aby ustalić, czy grupie nadrzędnej zadanie zostało anulowane.
cancel Metoda dotyczy tylko zadań podrzędnych.Na przykład, jeśli anulujesz grupy zadań tg1 na ilustracji drzewa równoległą pracę, wszystkie zadania w drzewie (t1, t2, t3, t4, i t5) jest narażony.Jeśli anulujesz grupy zagnieżdżonej zadań, tg2, tylko zadania t4 i t5 jest narażony.
Jeśli zadzwonisz pod cancel metoda, wszystkie zadania podrzędne grupy również są anulowane.Anulowanie nie wpływa jednak elementów nadrzędnych grupy zadań w drzewie równoległą pracę.Następujące przykłady przedstawiają to opierając się na ilustracji drzewa równoległą pracę.
Pierwszy z tych przykładów tworzy funkcję pracy dla zadania t4, która jest elementem podrzędnym grupy zadań tg2.Funkcja pracy wywołuje funkcję work w pętli.Jeśli którykolwiek zadzwonić do work się nie powiedzie, zadanie anuluje jego grupie nadrzędnej zadania.Powoduje to, że grupa zadań tg2 do wprowadzania stan Anulowane, lecz nie powoduje anulowania grupy zadań tg1.
auto t4 = make_task([&] {
// Perform work in a loop.
for (int i = 0; i < 1000; ++i)
{
// Call a function to perform work.
// If the work function fails, cancel the parent task
// and break from the loop.
bool succeeded = work(i);
if (!succeeded)
{
tg2.cancel();
break;
}
}
});
Ten drugi przykład podobny pierwszą z nich, chyba że grupa zadań anuluje zadanie tg1.This affects all tasks in the tree (t1, t2, t3, t4, and t5).
auto t4 = make_task([&] {
// Perform work in a loop.
for (int i = 0; i < 1000; ++i)
{
// Call a function to perform work.
// If the work function fails, cancel all tasks in the tree.
bool succeeded = work(i);
if (!succeeded)
{
tg1.cancel();
break;
}
}
});
structured_task_group Klasa nie jest wątków.W związku z tym, zadania podrzędne który wywołuje metodę nadrzędnego structured_task_group obiektu powoduje zachowanie nieokreślona.Wyjątkiem od tej reguły jest structured_task_group::cancel i concurrency::structured_task_group::is_canceling metody.Zadanie dziecko może wywołać te metody, aby anulować nadrzędna grupa zadań i sprawdź, czy odwołania.
Przestroga |
---|
Chociaż token odwołania można użyć, aby anulować pracę wykonywaną przez grupę zadań, który działa jako element podrzędny task obiektu, nie można używać task_group::cancel lub structured_task_group::cancel metod, aby anulować task obiektów, które są uruchamiane w grupę zadań. |
[U góry]
Korzystając z wyjątków, aby anulować czynność równoległą
Anulowanie tokeny i cancel metody są bardziej wydajne niż na anulowanie drzewa równoległą pracę obsługi wyjątków.Anulowanie tokenów i cancel metoda anulować zadanie i żadnych zadań podrzędnych w sposób góra dół.I odwrotnie obsługi wyjątków działa w sposób dół góra i musisz anulować każdej grupy zadań podrzędnych niezależnie jako wyjątek rozprzestrzenia się w górę.Temat Obsługa wyjątków we współbieżności środowiska wykonawczego wyjaśnia, jak w czasie wykonywania współbieżność używa wyjątki do komunikowania się błędy.Jednak nie wszystkie wyjątki, jeżeli wystąpił błąd.Na przykład algorytm wyszukiwania może anulować jej skojarzonego zadania po znalezieniu wynik.Jednakże, jak już wspomniano, obsługa wyjątków jest mniej skuteczne niż za pomocą cancel metoda aby anulować równoległą pracę.
Przestroga |
---|
Zaleca się używanie wyjątków do anulowania równoległą pracę tylko wtedy, gdy jest to konieczne.Anulowanie tokenów i grupy zadań cancel metody są bardziej skuteczne i mniej podatne na błąd. |
Gdy użytkownik wyjątek w treści funkcji pracy, który jest przekazywany do grupy zadań, środowiska wykonawczego przechowuje ten wyjątek i marszałków wyjątek od kontekstu, który czeka na grupy zadań do końca.Podobnie jak w przypadku cancel metoda, środowisko wykonawcze odrzuca wszystkie zadania, które nie zostały jeszcze rozpoczęte, a nie akceptuje nowych zadań.
W tym przykładzie trzeciego podobny drugi, z wyjątkiem tego zadania t4 zgłasza wyjątek, aby anulować grupy zadań, tg2.W poniższym przykładzie użyto try-catch bloku do sprawdzenia do anulowania podczas grupy zadań tg2 czeka na zakończenie jego zadań podrzędnych.Tak jak w pierwszym przykładzie, powoduje to grupy zadań tg2 do wprowadzania stan Anulowane, lecz nie powoduje anulowania grupy zadań tg1.
structured_task_group tg2;
// Create a child task.
auto t4 = make_task([&] {
// Perform work in a loop.
for (int i = 0; i < 1000; ++i)
{
// Call a function to perform work.
// If the work function fails, throw an exception to
// cancel the parent task.
bool succeeded = work(i);
if (!succeeded)
{
throw exception("The task failed");
}
}
});
// Create a child task.
auto t5 = make_task([&] {
// TODO: Perform work here.
});
// Run the child tasks.
tg2.run(t4);
tg2.run(t5);
// Wait for the tasks to finish. The runtime marshals any exception
// that occurs to the call to wait.
try
{
tg2.wait();
}
catch (const exception& e)
{
wcout << e.what() << endl;
}
W tym przykładzie czwartego wykorzystuje obsługi wyjątków do anulowania pracy całego drzewa.Przykład przechwytuje wyjątek podczas zadań grupy tg1 czeka na jego zadań podrzędnych do końca, a nie kiedy zadań grupy tg2 czeka na jego zadań podrzędnych.Jak w drugim przykładzie powoduje to obie grupy zadań w drzewie, tg1 i tg2, aby wprowadzić stan anulowane.
// Run the child tasks.
tg1.run(t1);
tg1.run(t2);
tg1.run(t3);
// Wait for the tasks to finish. The runtime marshals any exception
// that occurs to the call to wait.
try
{
tg1.wait();
}
catch (const exception& e)
{
wcout << e.what() << endl;
}
Ponieważ task_group::wait i structured_task_group::wait z metod generują podczas zadania podrzędne zgłasza wyjątek, nie otrzymasz od nich wartości zwracanej.
[U góry]
Anulowanie algorytmów równoległych
Równoległe algorytmy w PPL, na przykład, parallel_for, tworzenie grup zadań.W związku z tym służy wiele z tych samych metod do anulowania algorytm równoległy.
Poniższe przykłady ilustrują anulować algorytm równoległy na kilka sposobów.
W poniższym przykładzie użyto run_with_cancellation_token funkcji do wywołania parallel_for algorytm.run_with_cancellation_token Funkcja przyjmuje token jako argument o anulowaniu i wywołuje funkcję pracy pod warunkiem synchronicznie.Ponieważ algorytmy równoległe bazują na zadania, dziedziczą one token anulowanie zadania nadrzędnego.W związku z tym parallel_for może odpowiedzieć na anulowanie.
// cancel-parallel-for.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>
#include <sstream>
using namespace concurrency;
using namespace std;
int wmain()
{
// Call parallel_for in the context of a cancellation token.
cancellation_token_source cts;
run_with_cancellation_token([&cts]()
{
// Print values to the console in parallel.
parallel_for(0, 20, [&cts](int n)
{
// For demonstration, cancel the overall operation
// when n equals 11.
if (n == 11)
{
cts.cancel();
}
// Otherwise, print the value.
else
{
wstringstream ss;
ss << n << endl;
wcout << ss.str();
}
});
}, cts.get_token());
}
/* Sample output:
15
16
17
10
0
18
5
*/
W poniższym przykładzie użyto concurrency::structured_task_group::run_and_wait metodę do wywołania parallel_for algorytm.structured_task_group::run_and_wait Metoda czeka na podany na zakończenie zadania.structured_task_group Obiektu umożliwia funkcja pracy anulować zadanie.
// To enable cancelation, call parallel_for in a task group.
structured_task_group tg;
task_group_status status = tg.run_and_wait([&] {
parallel_for(0, 100, [&](int i) {
// Cancel the task when i is 50.
if (i == 50)
{
tg.cancel();
}
else
{
// TODO: Perform work here.
}
});
});
// Print the task group status.
wcout << L"The task group status is: ";
switch (status)
{
case not_complete:
wcout << L"not complete." << endl;
break;
case completed:
wcout << L"completed." << endl;
break;
case canceled:
wcout << L"canceled." << endl;
break;
default:
wcout << L"unknown." << endl;
break;
}
Ten przykład generuje następujące wyniki.
W poniższym przykładzie użyto wyjątek, aby anulować parallel_for pętli.Środowisko wykonawcze marszałków wyjątków kontekście wywołującego.
try
{
parallel_for(0, 100, [&](int i) {
// Throw an exception to cancel the task when i is 50.
if (i == 50)
{
throw i;
}
else
{
// TODO: Perform work here.
}
});
}
catch (int n)
{
wcout << L"Caught " << n << endl;
}
Ten przykład generuje następujące wyniki.
W poniższym przykładzie użyto flagę logiczną koordynowanie anulowania w parallel_for pętli.Każde zadanie jest uruchamiana, ponieważ w tym przykładzie nie korzysta z cancel obsługi metody lub wyjątek, aby anulować ogólny zestaw zadań.W związku z tym technika ta może mieć bardziej kosztem dodatkowego obciążenia związanego niż mechanizm anulowanie.
// Create a Boolean flag to coordinate cancelation.
bool canceled = false;
parallel_for(0, 100, [&](int i) {
// For illustration, set the flag to cancel the task when i is 50.
if (i == 50)
{
canceled = true;
}
// Perform work if the task is not canceled.
if (!canceled)
{
// TODO: Perform work here.
}
});
Każda metoda anulowania ma przewagę nad innymi.Wybierz metodę, która pasuje do określonych potrzeb.
[U góry]
Kiedy nie należy używać odwołania
Kiedy każdy członek grupy powiązanych zadań można zakończyć terminowo właściwe jest użycie anulowania.Istnieje jednak kilka scenariuszy, gdzie anulowania może nie być odpowiedni dla danej aplikacji.Na przykład ponieważ anulowanie zadania jest wspólne, ogólny zestaw zadań nie spowoduje anulowanie Zablokowanie wszelkich indywidualnych zadań.Na przykład jeśli jedno zadanie jeszcze się nie rozpoczęła, ale go odblokowuje innego zadania aktywne, nie rozpocznie Jeśli grupa zadań została anulowana.Może to spowodować zakleszczenie występuje w aplikacji.To drugi przykład gdzie korzystanie z anulowania nie może być właściwe jest, gdy zadanie zostało anulowane, ale jego zadań podrzędnych wykonuje operację ważne, takich jak zwalniania zasób.Ponieważ ogólny zestaw zadań jest anulowany po anulowaniu zadania nadrzędnego, tej operacji nie będzie wykonywał.Na przykład ilustruje tę sytuację, zobacz zrozumieć jak anulowania i wyjątek obsługi wpływa na obiekt zniszczenie sekcję w najlepszych praktyk w temacie równoległych Biblioteka wzorców.
[U góry]
Tematy pokrewne
Tytuł |
Opis |
---|---|
Pokazuje, jak użyć odwołania do implementacji algorytmu wyszukiwania równoległych. |
|
Porady: Użyj obsługi wyjątków, aby przerwać pętlę równoległą |
Pokazuje, jak użyć task_group klasy napisać algorytm wyszukiwania dla struktury drzewa podstawowe. |
W tym artykule opisano sposób czasu wykonywania obsługi wyjątków, które są generowane przez grupy zadań, lekki zadania i asynchronicznych agentów i sposobu odpowiedzi na wyjątki w aplikacjach. |
|
Równoległość zadania (współbieżność środowiska wykonawczego) |
W tym artykule opisano, jak zadania odnoszą się do grup zadań i jak można użyć strukturalnych i niestrukturalnych zadań w aplikacji. |
W tym artykule opisano równoległych algorytmów, które jednocześnie wykonywania pracy na zbiory danych |
|
Zawiera omówienie równoległych Biblioteka wzorców. |
Odwołanie
task — Klasa (współbieżność środowiska wykonawczego)