Udostępnij za pośrednictwem


Anulowanie w PPL

W tym dokumencie omówiono roli anulowania równoległych biblioteki wzorców (PPL), jak anulować równolegle i sposobu ustalania, kiedy anulowany równoległych pracy.

[!UWAGA]

Środowisko wykonawcze używa obsługi wyjątków do zaimplementowania anulowania.Catch lub nie obsługiwać tych wyjątków w kodzie.Ponadto zaleca się, aby napisać kod wyjątku bezpieczne w organach funkcji dla zadań.Na przykład można użyć Zasobów nabycia jest inicjowania wzoru (RAII) w celu zapewnienia, że zasoby są obsługiwane poprawnie gdy wyjątek w treści zadania.Pełny przykład używa wzorca RAII oczyszczenie zasobu do zadania cancelable, zobacz Instruktaż: Usuwanie pracy z wątku interfejsu użytkownika.

Punkty klucza

W tym dokumencie

  • Równoległe drzew pracy

  • Anulowanie zadania równolegle

    • Równoległe anulować przy użyciu tokenu odwołania

    • Za pomocą Anuluj metoda anulować równoległych pracy

    • Równoległe anulować za pomocą wyjątków

  • Anulowanie algorytmy równoległe

  • Kiedy nie używać anulowania

Równoległe drzew pracy

PPL używa zadań i grup zadań Zarządzanie zadaniami szczegółowymi i obliczenia.Można zagnieździć grup zadań do formularza drzew pracy równolegle.Na następującej ilustracji pokazano drzewo równoległych pracy.Na tej ilustracji tg1 i tg2 reprezentują grupy zadań; t1, t2, t3, t4, i t5 reprezentują grupy zadań wykonywania pracy.

Drzewo równoległą pracę

Poniższy przykład zawiera kod, który jest wymagany do utworzenia w drzewie na ilustracji.W tym przykładzie tg1 i tg2concurrency::structured_task_group obiektów; 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 Tworzenie drzewa podobne prace.Concurrency::task klasy obsługuje również pojęcia drzewa pracy.Jednakże task drzewa jest drzewo zależności.W task drzewie przyszłych prac kończy się po bieżących prac.W drzewie grupy zadań wewnętrznych prac kończy się przed zewnętrznym.Aby uzyskać więcej informacji o różnicach między zadaniami i grup zadań, zobacz Zadanie równoległości (współbieżności Runtime).

Top

Anulowanie zadania równolegle

Aby anulować równolegle wiele sposobów.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.Sposób końcowy jest zgłaszanie wyjątku w treści funkcji pracy zadania.Bez względu na wybraną metodę należy zrozumieć, że unieważnienie nie występuje natychmiast.Chociaż nowej pracy nie jest uruchomiona, jeśli zadanie lub grupy zadań zostanie anulowana, aktywnej pracy musi sprawdzić i odpowiada na anulowanie.

Więcej przykładów, które anulować zadania równolegle, zobacz Przewodnik: Łączenie, za pomocą zadań i żądania HTTP XML (IXHR2), Jak: umożliwia anulowanie podziału z pętli równoległe, i Jak: Użyj obsługi wyjątków do podziału z pętli równoległe.

Dd984117.collapse_all(pl-pl,VS.110).gifRównoległe anulować przy użyciu tokenu odwołania

task, task_group, I structured_task_group klasy obsługuje anulowania przy użyciu tokenów anulowania.Definiuje PPL concurrency::cancellation_token_source i concurrency::cancellation_token klasy w tym celu.Użycie tokenu odwołania do anulowania pracy runtime nie uruchamia subskrybuje token nowej pracy.Praca, która jest już aktywny można monitorować token jej anulowania i Zatrzymaj, gdy można go.

Zainicjować anulowanie wywołania concurrency::cancellation_token_source::cancel metody.Możesz odpowiedzieć na anulowanie w następujący sposób:

W poniższym przykładzie pierwsze podstawowy wzorzec dla anulowanie zadania.Jednostka zadań sprawdza czasami anulowania 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 Działać rzuca; dlatego nie trzeba jawnie powrócić z bieżącej pętli lub funkcji.

PoradaPorada

Alternatywnie, można wywołać concurrency::interruption_point działać zamiast is_task_cancellation_requested i cancel_current_task.

Ważne wywołanie jest cancel_current_task podczas odpowiedzi na anulowanie ponieważ przejścia to zadanie, stan Anulowane.Jeśli można zwracać wczesne telefonicznej cancel_current_task, operacja przejścia do stanu zakończone i wszelkie kontynuacji oparta na wartości są uruchamiane.

Informacje dotyczące przestrogiPrzestroga

Throw nigdy nie task_canceled z kodu.Wywołanie cancel_current_task zamiast.

Gdy zadanie kończy się w stanie anulowane, concurrency::task::get metoda generuje concurrency::task_canceled.(I odwrotnie, concurrency::task::wait zwraca task_status::canceled i nie.) Poniższy przykład ilustruje to zachowanie dla kontynuacji opartych na zadaniach.Kontynuacja opartych na zadaniach zawsze nosi, nawet wtedy, gdy zadanie antecedent jest anulowana.

// 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ż kontynuacji wartość oparta dziedziczą token ich zadań antecedent, chyba że zostały utworzone z tokenem jawne, kontynuacji natychmiast wprowadzić stan Anulowane, nawet wtedy, gdy nadal wykonywane jest zadanie antecedent.Dlatego wyjątek, który jest generowany przez zadanie antecedent po unieważnieniu nie są propagowane do kontynuacji zadań.Anulowanie zawsze zastępuje stan zadania antecedent.Poniższy przykład podobny do poprzedniego, ale ilustruje zachowanie dla kontynuacji oparta na wartości.

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.
*/
Informacje dotyczące przestrogiPrzestroga

Jeśli nie przechodzą tokenu odwołania do task konstruktora lub concurrency::create_task funkcji, to zadanie nie jest anulowanie.Ponadto trzeba przekazać samego tokenu odwołania do konstruktora żadnych zadań zagnieżdżonych (to znaczy zadania utworzone w treści innego zadania), aby anulować wszystkie zadania jednocześnie.

Może być uruchomienie dowolnego kodu po anulowaniu token anulowania.Na przykład, jeśli użytkownik wybierze anulowanie przycisku na interfejs użytkownika, aby anulować operację, można wyłączyć tego przycisku aż użytkownik uruchamia innej operacji.Poniższy przykład pokazuje, jak używać concurrency::cancellation_token::register_callback metody zarejestrować funkcji zwrotnej, która jest uruchamiana po anulowaniu token anulowania.

// 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 Zadanie równoległości (współbieżności Runtime) wyjaśnia różnicy między kontynuacji wartość i zadania.Jeśli nie podasz cancellation_token obiektu zadania kontynuacji, kontynuacji dziedziczy tokenu odwołania antecedent zadania w następujący sposób:

  • Wartość oparta kontynuacji zawsze dziedziczy tokenu odwołania antecedent zadania.

  • Kontynuacja opartych na zadaniach nigdy nie dziedziczy tokenu odwołania antecedent zadania.Jedynym sposobem, aby cancelable kontynuacji opartych na zadaniach jest jawnie przekazanie token anulowania.

Błędna zadania (to jest taką, która zgłasza wyjątek) nie dotyczy tych zachowań.W przypadku kontynuacji wartość oparta jest anulowane; kontynuacja opartych na zadaniach nie została anulowana.

Informacje dotyczące przestrogiPrzestroga

Zadania utworzonego w innego zadania (innymi słowy, zadanie zagnieżdżonych) nie dziedziczą token anulowanie zadania nadrzędnego.Tylko oparta na wartości utrzymania dziedziczy tokenu odwołania antecedent zadania.

PoradaPorada

Użyj concurrency::cancellation_token:: Brak metody po wywołaniu konstruktora lub funkcji, która ma cancellation_token obiektu i nie ma być anulowanie operacji.

Można również podać tokenu odwołania do konstruktora task_group lub structured_task_group obiektu.Ważnym aspektem tego jest, że grupy zadań podrzędnych dziedziczy ten token anulowania.Na przykład, który demonstruje tę koncepcję za pomocą concurrency::run_with_cancellation_token do wywołania funkcji parallel_for, zobacz Algorytmy równoległe anulowanie później w tym dokumencie.

Top

Dd984117.collapse_all(pl-pl,VS.110).gifAnulowanie tokenów i skład zadania

Concurrency::when_all i concurrency::when_any funkcje mogą pomóc w wielu zadań do wykonania typowe wzorce redagowania.W tej sekcji opisano, jak pracować anulowania tokeny te funkcje.

Kiedy dostarczyć token anulowania albo when_all i when_any działać, że funkcja anuluje tylko, gdy token anulowania zostanie anulowana lub gdy jeden uczestnik zadań kończy się w stanie anulowane lub zgłasza wyjątek.

when_all Funkcji dziedziczy token anulowania każdego zadania, który redaguje ogólnej operacji, gdy dostarcza tokenu odwołania do niego.Zadanie jest zwracane z when_all została anulowana podczas żadnego z tych tokeny są anulowane i co najmniej jeden uczestnik zadań nie została jeszcze uruchomiona lub jest uruchomiony.Podobne zachowanie występuje, gdy zadanie jest zwracane z jednym z zadań zgłasza wyjątek – when_all jest natychmiast anulowane z tego wyjątku.

Środowisko wykonawcze wybiera token anulowanie zadania, która jest zwracana when_any działać po zakończeniu tego zadania.Jeśli żaden uczestnik zadania Zakończ w stanie zakończone i jeden lub więcej zadań zgłasza wyjątek, jednym z zadań, które wywołało wybrano zakończenie when_any i jego token jest wybrany jako zadania końcowego tokenu.Jeżeli więcej niż jedno zadanie kończy się w wypełniony Państwo, zadanie jest zwracane z when_any zadanie kończy się w stanie zakończone.Próbuje pobrania tokenu, którego nie zostało anulowane w chwili zakończenia tak, że zadanie jest zakończone zadanie wykonywania zwrócony z when_any nie jest natychmiast anulowane, nawet jeśli inne wykonującego zadania może zostać ukończone w przyszłości.

Top

Dd984117.collapse_all(pl-pl,VS.110).gifZa pomocą Anuluj metoda anulować równoległych pracy

Concurrency::task_group::cancel i concurrency::structured_task_group::cancel metody ustawić grupy zadań stan Anulowane.Po wywołaniu cancel, grupy zadań nie uruchamia zadania w przyszłości.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.

Grupy zadań zostało anulowane, może wyzwolić wywołań z każdego zadania podrzędne w czasie wykonywania punkt przerwania, co powoduje, że runtime throw i połowu typu wewnętrzny wyjątek, aby anulować zadania aktywne.Runtime współbieżności nie definiuje punktów przerwania szczególnych; występują w każde wywołanie środowiska wykonawczego.Środowisko wykonawcze muszą obsługiwać wyjątków, które generuje go do wykonania anulowania.Dlatego nie obsługują nieznany wyjątki w treści zadania.

Jeśli zadania podrzędne wykonuje operację czasochłonne i nie wywołuje w czasie wykonywania, należy okresowo Sprawdź anulowania i zakończyć terminowo.Poniższy przykład przedstawia sposób określić podczas pracy jest anulowana.Zadanie t4 anuluje nadrzędnego grupy zadań, gdy napotka błąd.Zadanie t5 sporadycznie wywołuje structured_task_group::is_canceling metody sprawdzania unieważnienia.Zadanie zostało anulowane nadrzędnego grupy zadań, t5 drukuje 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, czy unieważnienie co 100cz iteracji pętli zadania.Częstotliwość, z jaką sprawdzania unieważnienia zależy od ilości pracy, który wykonuje zadania i jak szybko należy odpowiedzieć na anulowanie zadania.

Jeśli nie masz dostępu do obiektu nadrzędnego grupy zadań, wywołanie concurrency::is_current_task_group_canceling funkcji, czy nadrzędna grupa 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łych pracy wszystkich zadań w drzewie (t1, t2, t3, t4, i t5) dotyczy.Jeśli anulujesz grupy zagnieżdżone zadań tg2, tylko zadań t4 i t5 dotyczy.

Po wywołaniu cancel metody, wszystkie zadania podrzędne grupy są również anulowane.Anulowanie nie wpływa jednak wszelkie rodziców grupy zadań w drzewie równoległych pracy.Następujące przykłady przedstawiają to tworząc na ilustracji drzewa równoległych pracy.

Pierwszy z tych przykładów tworzy funkcję pracy dla zadania t4, która jest elementem podrzędnym grupy zadań tg2.Funkcja pracę wywołuje funkcję work w pętli.Jeśli dowolny wywołanie work nie powiedzie się, zadanie anuluje jego nadrzędnego grupy zadań.Powoduje to grupy zadań tg2 wprowadzić stan Anulowane, ale nie anuluje zadania grupy 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 przypomina pierwsza, chyba że zadanie anuluje grupy zadań 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 bezpieczne wątek.Dlatego zadania podrzędne, wywołuje metodę nadrzędnego structured_task_group obiektu powoduje zachowanie nieokreślone.Wyjątki od tej reguły są structured_task_group::cancel i concurrency::structured_task_group::is_canceling metody.Zadania podrzędne mogą wywoływać te metody, aby anulować nadrzędna grupa zadań i sprawdź, czy unieważnienie.

Informacje dotyczące przestrogiPrzestroga

Chociaż można anulować pracę wykonywaną przez grupy zadań, który działa jako element podrzędny token anulowanie task obiektu, nie można użyć task_group::cancel lub structured_task_group::cancel metod, aby anulować task obiektów, które są uruchamiane w grupy zadań.

Top

Dd984117.collapse_all(pl-pl,VS.110).gifRównoległe anulować za pomocą wyjątków

Użycie tokenów anulowania i cancel metody są bardziej wydajne niż obsługi na anulowanie drzewa równoległych pracy wyjątków.Anulowanie tokenów i cancel metody anulowanie wszystkich zadań podrzędnych i zadania w sposób góra dół.Odwrotnie obsługi wyjątków działa w sposób oddolnego i anulować każdej grupy zadań podrzędnych niezależnie jako wyjątek propaguje w górę.Temat Obsługa wyjątków w Runtime współbieżności wyjaśnia, jak Runtime współbieżności używa wyjątki do komunikowania się błędy.Jednak nie wszystkie wyjątki wskazać 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ż przy użyciu cancel metoda anulować równolegle.

Informacje dotyczące przestrogiPrzestroga

Zaleca się używać wyjątki anulować równoległych pracy tylko wtedy, gdy jest to konieczne.Anulowanie tokenów i grupy zadań cancel metody są bardziej skuteczne i mniej podatne na błędy.

Gdy wyjątek w treści funkcji pracy, która przekazuje rzucać się do grupy zadań, runtime przechowuje ten wyjątek i marshals wyjątek kontekst czeka na zakończenie grupy zadań.Tak jak w cancel metody wykonywania odrzuca wszelkie zadania, które nie zostały jeszcze uruchomiona i nie akceptuje nowych zadań.

Trzecim przykładzie podobny do drugiej, z wyjątkiem zadania t4 zgłasza wyjątek, aby anulować grupy zadań tg2.W tym przykładzie try-catch bloku, aby sprawdzić, czy unieważnienie podczas grupy zadań tg2 czeka na zakończenie jego zadań podrzędnych.Podobnie jak w pierwszym przykładzie powoduje grupy zadań tg2 wprowadzić stan Anulowane, ale nie anuluje zadania grupy 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;
}

Ten przykład czwarty używa obsługi wyjątków anulować pracę całego drzewa.Przykład przechwytuje wyjątek podczas zadań grupy tg1 czeka na jego zadań podrzędnych do zakończenia, a nie kiedy zadań grupy tg2 czeka na jego zadań podrzędnych.Podobnie 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 metod generują podczas zadania podrzędne zgłasza wyjątek, nie otrzymasz zwrotu wartości od nich.

Top

Anulowanie algorytmy równoległe

Równoległe algorytmów w PPL, na przykład parallel_for, tworzenie grup zadań.Dlatego można wiele z tych samych technik anulować algorytmu równoległego.

Poniższe przykłady ilustrują anulować algorytmu równoległego 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 Trwa anulowanie token jako argument i wywołuje przewidziano funkcji pracy synchronicznie.Ponieważ algorytmy równoległe zbudowane są na zadania, dziedziczą one token anulowanie zadania nadrzędnego.Dlatego parallel_for może reagować 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 wywołania metody parallel_for algorytm.structured_task_group::run_and_wait Metody czeka na zakończenie zadania dostarczone.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.

The task group status is: canceled.

W poniższym przykładzie użyto wyjątek, aby anulować parallel_for pętli.Środowisko wykonawcze marshals wyjątek 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.

Caught 50

W poniższym przykładzie użyto flagę logiczną koordynowania anulowania w parallel_for pętli.Każde zadanie uruchamia, ponieważ w tym przykładzie nie korzysta z cancel metody lub wyjątek obsługa anulować ogólny zestaw zadań.Technika ta może więc bardziej obliczeniowa obciążenie 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.

Top

Kiedy nie używać anulowania

Właściwe jest stosowanie anulowania podczas każdego członka grupy powiązanych zadań można zakończyć terminowo.Istnieją jednak niektórych scenariuszach, gdy unieważnienie nie mogą być właściwe dla aplikacji.Na przykład ponieważ anulowanie zadania współpracy, ogólny zestaw zadań nie spowoduje anulowanie Jeśli wszelkich poszczególnych zadań jest zablokowany.Na przykład jeśli jedno zadanie nie została jeszcze uruchomiona, ale go odblokowuje innego zadania aktywne, to nie uruchomi grupy zadań zostało anulowane.Może to spowodować zakleszczenie występuje w aplikacji.Drugi przykład gdzie stosowanie anulowania nie może być właściwe jest zadanie zostało anulowane, ale jego zadań podrzędnych wykonuje operację ważne, na przykład zwalniania zasób.Ponieważ całkowita zestawu zadań jest anulowany po anulowaniu zadania nadrzędnego, nie wykona operacji.Przykład ilustruje tę, zobacz Understand how Cancellation and Exception Handling Affect Object Destruction sekcji najlepszych praktyk w temacie równoległych biblioteki wzorców.

Top

Tematy pokrewne

Tytuł

Opis

Jak: umożliwia anulowanie podziału z pętli równoległe

Pokazuje, jak używać odwołania do wdrożenia algorytm wyszukiwania równolegle.

Jak: Użyj obsługi wyjątków do podziału z pętli równoległe

Pokazuje, jak użyć task_group klasy do zapisu algorytm wyszukiwania dla struktury drzewa podstawowe.

Obsługa wyjątków w Runtime współbieżności

W tym artykule opisano sposób wykonywania obsługi wyjątków, które są generowane przez grupy zadań, lekkie zadania i asynchronicznych agentów i sposobu odpowiedzi na wyjątki w aplikacji.

Zadanie równoległości (współbieżności Runtime)

Opisuje, jak zadania odnoszą się do grup zadań i jak używać zadań strukturalnych i niestrukturalnych w aplikacji.

Algorytmy równoległe

Opisuje algorytmy równoległe, które jednocześnie wykonywać pracę na zbiory danych

Biblioteka desenie równoległe (PPL)

Zawiera omówienie równoległych biblioteki wzorców.

Odwołanie

zadanie klasy (współbieżności Runtime)

Klasa cancellation_token_source

Klasa cancellation_token

Klasa task_group

Klasa structured_task_group

Funkcja parallel_for