Compartilhar via


Cancelar o PPL

Este documento explica a função cancelar na biblioteca (PPL) dos padrões de paralela, como cancelar o trabalho paralelo, e como determinar quando o trabalho de paralela é cancelado.

ObservaçãoObservação

O tempo de execução usa a manipulação de exceção para implementar o botão.Não capturar ou não tratar essas exceções em seu código.Além disso, recomendamos que você escreve o código de manipulação de segurança em corpos função para suas tarefas.Por exemplo, você pode usar o padrão Aquisição de recurso é inicialização (RAII) para garantir que os recursos são tratados corretamente quando uma exceção é lançada no corpo de uma tarefa.Para um exemplo completo que usa o padrão de RAII para limpar um recurso em uma tarefa anulável, consulte Passo a passo: Removendo o trabalho de um encadeamento de interface do usuário.

Chave

  • O botão é cooperativo e envolve a coordenação entre o código que solicita o botão e a tarefa que responde ao botão.

  • Quando possível, tokens cancelar de uso para cancelar o trabalho.A classe de concurrency::cancellation_token define um token cancelar.

  • Quando você usa tokens cancelar, use o método de concurrency::cancellation_token_source::cancel para iniciar o botão e funções de concurrency::is_task_cancellation_requested e de concurrency::cancel_current_task para responder ao botão.

  • O botão não acontece imediatamente.Embora o trabalho não é iniciada se uma tarefa ou um grupo de trabalho serão canceladas, o trabalho ativa deve verificar e responder a cancelar.

  • Uma continuação valor base herda o símbolo de cancelamento de sua tarefa antecedente.Continuação uma chave com base nunca herda o símbolo de sua tarefa antecedente.

  • Use o método de concurrency::cancellation_token::none quando você chama um construtor ou funções que recebe um objeto de cancellation_token mas você não deseja que a operação para ser cancellable.Além disso, se você não passa um token cancelar ao construtor de concurrency::task ou à função de concurrency::create_task , essa tarefa não é cancellable.

Neste documento

  • Árvores paralelas de trabalho

  • Cancelando tarefas paralelas

    • Usando um token cancelar para cancelar o trabalho paralelo

    • Usando o método cancelar para cancelar o trabalho paralelo

    • Usando exceções para cancelar o trabalho paralelo

  • Cancelando algoritmos paralelos

  • Quando não usar o para cancelar

Árvores paralelas de trabalho

O PPL usa tarefas e grupos de trabalho gerenciar tarefas refinados e cálculos.Você pode aninhar grupos de trabalho para formar árvores de trabalho paralelo.A ilustração a seguir mostra uma árvore paralela de trabalho.Nesta ilustração, tg1 e tg2 representam grupos de trabalho; t1, t2, t3, t4, e t5 representam o trabalho que os grupos de trabalho são executadas.

Uma árvore de trabalho paralelos

O exemplo a seguir mostra o código que é necessário para criar a árvore na ilustração.Nesse exemplo, tg1 e tg2 são objetos de concurrency::structured_task_group ; t1, t2, t3, t4, e t5 são objetos de concurrency::task_handle .

// 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();   
}

Você também pode usar a classe de concurrency::task_group para criar uma árvore semelhante de trabalho.A classe de concurrency::task também oferece suporte a noção de uma árvore de trabalho.No entanto, uma árvore de task é uma árvore de dependência.Em uma árvore de task , o trabalho futuros completa após o trabalho atual.Em uma árvore de grupo de trabalho, o trabalho interno terminar antes de trabalho externo.Para obter mais informações sobre as diferenças entre tarefas e grupos de trabalho, consulte Paralelismo de tarefa (tempo de execução de simultaneidade).

Superior[]

Cancelando tarefas paralelas

Há várias maneiras de cancelar o trabalho paralelo.A maneira preferencial é usar um token cancelar.Os grupos de trabalho também suportam o método de concurrency::task_group::cancel e o método de concurrency::structured_task_group::cancel .A forma final é lançar uma exceção no corpo de uma função de trabalho de tarefas.Não importa o método que você escolher, que compõem o botão não acontece imediatamente.Embora o trabalho não é iniciada se uma tarefa ou um grupo de trabalho serão canceladas, o trabalho ativa deve verificar e responder a cancelar.

Para obter mais exemplos que cancelarem tarefas paralelas, consulte Passo a passo: Conectando-se com tarefas e solicitação de HTTP de XML (IXHR2), Como: Use o botão para interromper de um loop paralelo, e Como: Use manipulação de exceção para interromper de um loop paralelo.

Dd984117.collapse_all(pt-br,VS.110).gifUsando um token cancelar para cancelar o trabalho paralelo

task, task_group, e as classes de structured_task_group suportam cancelamento com o uso de símbolos cancelar.O PPL define as classes de concurrency::cancellation_token_source e de concurrency::cancellation_token essa finalidade.Quando você usa um token cancelar para cancelar o trabalho, o tempo de execução não começa a trabalho que a assinatura esse token.Trabalhar que já está ativa pode monitorar o símbolo de cancelar o e parar quando possa.

Para iniciar cancelamento, chame o método de concurrency::cancellation_token_source::cancel .Você reponde ao cancelamento das seguintes maneiras:

O exemplo a seguir mostra o primeiro padrão básico para cancelamento de tarefas.O corpo da tarefa ocasionalmente verifica a existência de cancelamento dentro de um loop.

// 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.
*/

O gera de função de cancel_current_task ; como consequência, você não precisa retornar do loop atual ou explicitamente de funcionar.

DicaDica

Como alternativa, você pode chamar a função de concurrency::interruption_point em vez de is_task_cancellation_requested e de cancel_current_task.

É importante chamar cancel_current_task quando você reponde ao cancelamento porque faz a transição da tarefa ao estado cancelado.Se você retorna no início em vez de chamada cancel_current_task, a operação faz a transição de estado completo e todas as continuações valor com base são executadas.

Observação de cuidadoCuidado

Nunca lançar task_canceled do seu código.Chame o cancel_current_task em vez disso.

Quando terminar de tarefa no estado cancelado, o método de concurrency::task::get jogarem concurrency::task_canceled.(Por outro lado, concurrency::task::wait retorna task_status::canceled e não o gera uma.) O exemplo a seguir ilustra esse comportamento para uma continuação chave com base.Continuação uma chave com base é chamada sempre, mesmo quando a tarefa antecedente é cancelada.

// 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.
*/

Porque as continuações valor com base herda o símbolo de sua tarefa antecedente a menos que eles sejam criadas com um símbolo explícito, as continuações passa imediatamente no estado cancelado mesmo quando a tarefa antecedente ainda está sendo executado.Como consequência, qualquer exceção que é lançada por tarefa antecedente depois que o botão não é propagado para continuar tarefas.Cancelamento substitui sempre o estado de tarefa antecedente.O exemplo a seguir é semelhante ao exemplo anterior, mas ilustra-se o comportamento para uma continuação valor base.

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.
*/
Observação de cuidadoCuidado

Se você não passa um token cancelar ao construtor de task ou à função de concurrency::create_task , essa tarefa não é cancellable.Além disso, você deve passar o mesmo token cancelar ao construtor de todas as tarefas aninhado (isto é, tarefas que são criadas no corpo de outra tarefa) cancelar simultaneamente todas as tarefas.

Você pode desejar executar o código arbitrário quando um token cancelar for cancelado.Por exemplo, se o usuário escolhe um botão de Cancelar na interface do usuário para cancelar a operação, você pode desativar esse botão até que o usuário inicie uma operação novamente.O exemplo a seguir mostra como usar o método de concurrency::cancellation_token::register_callback para registrar um função de retorno de chamada que é executado quando um token cancelar for cancelado.

// 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.
*/

O documento Paralelismo de tarefa (tempo de execução de simultaneidade) explica a diferença entre continuações valor com base e chave com base.Se você não fornecer um objeto de cancellation_token a uma tarefa de continuação de linha, a continuação herda o símbolo de cancelamento de tarefa antecedente das seguintes maneiras:

  • Uma continuação valor base herda sempre o símbolo de cancelamento de tarefa antecedente.

  • Continuação uma chave com base nunca herda o símbolo de cancelamento de tarefa antecedente.A única maneira de fazer uma continuação chave com base anulável é passar explicitamente um token cancelar.

Esses comportamentos não são afetados por uma tarefa criticada (ou seja, uma que lança uma exceção).Nesse caso, uma continuação valor base é cancelada; continuação uma chave com base não é cancelada.

Observação de cuidadoCuidado

Uma tarefa que é criada em outra tarefa (ou é uma tarefa aninhada) não herda o símbolo de cancelamento de tarefa pai.Somente uma continuação valor base herda o símbolo de cancelamento de sua tarefa antecedente.

DicaDica

Use o método de concurrency::cancellation_token::none quando você chama um construtor ou funções que recebe um objeto de cancellation_token e você não desejar que a operação para ser cancellable.

Você também pode fornecer um token cancelar para o construtor de um objeto de task_group ou de structured_task_group .Um aspecto importante disso é que os grupos de trabalho filhos herdam este token cancelar.Para um exemplo que demonstra este conceito usando a função de concurrency::run_with_cancellation_token para executar para chamar parallel_for, consulte Cancelando algoritmos paralelos mais tarde neste documento.

Superior[]

Dd984117.collapse_all(pt-br,VS.110).gifTokens cancelar e configurações da tarefa

Funções de concurrency::when_all e de concurrency::when_any podem ajudá-lo a composição várias tarefas implementar padrões comuns.Esta seção descreve como essas funções funcionam com tokens cancelar.

Quando você fornecer um token cancelar ao ou a função de when_all e de when_any , cancelamentos dessa função somente quando esse token cancelar é cancelado ou quando uma das extremidades de tarefas de participante em um estado cancelado ou lançar uma exceção.

A função de when_all herda o símbolo de cancelamento de cada tarefa que compõem a operação total quando você não lhe fornece um token cancelar.A tarefa que é retornada de when_all é cancelada quando qualquer um desses símbolos serão canceladas e pelo menos um participante das tarefas que ainda não seguir o iniciarão nem estão executando.Um comportamento similar ocorre quando uma das tarefas lança uma exceção – a tarefa que é retornada de when_all será cancelada imediatamente com essa exceção.

O tempo de execução escolher o símbolo para cancelar a tarefa que é retornada de função de when_any quando a tarefa termina.Se nenhuma das tarefas de participante completa em um estado completo e uma ou mais das tarefas lança uma exceção, uma das tarefas que jogaram é escolhida para concluir when_any e o símbolo é escolhido como o símbolo para a tarefa final.Se mais de uma tarefa termina no estado concluído, a tarefa que é retornada termina de tarefa de when_any em um estado concluído.Tentativas de tempo de execução para escolher uma tarefa concluída cujo token não é cancelado no momento de conclusão de modo que a tarefa que é retornada de when_any não são canceladas imediatamente mesmo que outras tarefas podem concluir executando em um momento posterior.

Superior[]

Dd984117.collapse_all(pt-br,VS.110).gifUsando o método cancelar para cancelar o trabalho paralelo

Os métodos de concurrency::task_group::cancel e de concurrency::structured_task_group::cancel definem um grupo de trabalho para o estado cancelado.Depois de você chamar cancel, o grupo de trabalho não começa as tarefas futuras.Os métodos de cancel podem ser chamados por várias tarefas filhos.Uma tarefa cancelada faz com que os métodos de concurrency::task_group::wait e de concurrency::structured_task_group::wait retorna concurrency::canceled.

Se um grupo de trabalho é cancelado, chamadas de cada tarefa filho em tempo de execução podem disparar um ponto de interrupção, que faz com que o tempo de execução lança e captura um tipo de exceção interna para cancelar tarefas ativas.O tempo de execução de simultaneidade não define determinados pontos de interrupção; podem ocorrer em qualquer chamada para o tempo de execução.O tempo de execução deve tratar exceções que gera para executar o botão.Como consequência, não manipular exceções desconhecidas no corpo de uma tarefa.

Se uma tarefa filho executa uma operação demorada e não a chama em tempo de execução, periodicamente deve verificar o botão e sair em tempo hábil.O exemplo a seguir mostra uma maneira de determinar quando o trabalho é cancelado.A tarefa t4 cancela o grupo de trabalho pai quando encontra um erro.A tarefa t5 ocasionalmente chama o método de structured_task_group::is_canceling para verificar o botão.Se o grupo de trabalho pai é cancelado, a tarefa t5 imprime uma mensagem e sai.

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();

Este exemplo verifica o botão em cada iteração do loop 100th de tarefas.A frequência com que você verifica cancelamento dependem da quantidade de trabalho que sua tarefa é executada e como rapidamente você precisa para as tarefas que respondam ao botão.

Se você não tem acesso ao objeto pai do grupo de trabalho, chame a função de concurrency::is_current_task_group_canceling para determinar se o grupo de trabalho pai é cancelado.

O método de cancel afeta somente tarefas filhos.Por exemplo, se você cancelar o grupo de trabalho tg1 na árvore mostrada paralela de trabalho, todas as tarefas na árvore (t1, t2, t3, t4, e t5) são afetadas.Se você cancelar o grupo de trabalho aninhado, tg2, somente as tarefas t4 e t5 são afetadas.

Quando você chama o método de cancel , todos os grupos de trabalho filhos serão canceladas também.No entanto, o botão não afeta os pais de grupo de trabalho em uma árvore paralela de trabalho.Os exemplos a seguir mostram este compilando na ilustração paralela a árvore de trabalho.

O primeiro desses exemplos a seguir cria uma função de trabalho para a tarefa t4, que é um filho do grupo de trabalho tg2.As chamadas de função de trabalho a função work em um loop.Se qualquer chamada a work falhar, a tarefa cancela o grupo de trabalho pai.Isso faz com que o grupo de trabalho tg2 no estado entre cancelado, mas não cancela o grupo de trabalho 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;
      }
   }         
});

Como esse exemplo é semelhante ao primeiro, exceto que ao grupo de trabalho tg1de cancelamentos de tarefas.Isso afeta todas as tarefas na árvore (t1, t2, t3, t4, e 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;
      }
   }   
});

A classe de structured_task_group não é segura.Como consequência, uma tarefa filho que chama um método do objeto de structured_task_group do pai gera o comportamento não especificado.Exceções a essa regra são os métodos de structured_task_group::cancel e de concurrency::structured_task_group::is_canceling .Uma tarefa filho pode chamar esses métodos para cancelar o grupo de trabalho e verificação pai para o botão.

Observação de cuidadoCuidado

Embora você possa usar um token o botão cancelar que o trabalho é executado por um grupo de trabalho que executa como um filho de um objeto de task , você não pode usar os métodos de task_group::cancel ou de structured_task_group::cancel cancelar os objetos de task que executam em um grupo de trabalho.

Superior[]

Dd984117.collapse_all(pt-br,VS.110).gifUsando exceções para cancelar o trabalho paralelo

O uso de símbolos e cancelar o método de cancel são mais eficiente do que a manipulação de exceção em cancelar uma árvore paralela de trabalho.Os tokens cancelar e o método de cancel cancelarem uma tarefa e todas as tarefas de filho de uma maneira top-down.Por outro lado, o trabalho de manipulação de exceção de uma maneira de cima para baixo e devem cancelar cada grupo de trabalho filho independente como as se propaga de exceção para cima.O tópico Manipulação de exceção em tempo de execução de concorrência explica como o tempo de execução exceções concorrentes usa para se comunicar erros.No entanto, nem todas as exceções indicam um erro.Por exemplo, um algoritmo de pesquisa pode cancelar a tarefa associada quando encontrar o resultado.No entanto, como mencionado anteriormente, manipulação de exceção é menos eficiente do que usar o método de cancel para cancelar o trabalho paralelo.

Observação de cuidadoCuidado

É recomendável que você use exceções para cancelar o trabalho paralelo somente quando necessário.Os tokens cancelar e métodos de cancel de grupo de trabalho são um erro mais eficiente e menos propenso.

Quando você gera uma exceção no corpo de uma função de trabalho que você passe a um grupo de trabalho, o tempo de execução que armazena exceção e controla a exceção ao contexto que espera o grupo de trabalho para concluir.Como com o método de cancel , o tempo de execução descarta todas as tarefas que ainda não começarem, e não aceita novas tarefas.

Este exemplo lembra o terceiro segundo, exceto que a de t4 gera uma exceção de tarefas para cancelar o grupo de trabalho tg2.Este exemplo usa um bloco de try- decatch para verificar o botão quando o grupo de trabalho tg2 espera suas tarefas filhos concluir.Como o primeiro exemplo, isso faz com que o grupo de trabalho tg2 no estado entre cancelado, mas não cancela o grupo de trabalho 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;
}

A quarta manipulação de exceção do exemplo usa para cancelar a árvore de trabalho inteiro.O exemplo captura a exceção quando o grupo de trabalho tg1 espera filhos concluir suas tarefas em vez de quando o grupo de trabalho tg2 espera suas tarefas filhos.Como o segundo exemplo, isso faz com que ambos os grupos de tarefas na árvore, em tg1 e em tg2, façam logon no estado cancelado.

// 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;
}

Como os métodos de task_group::wait e de structured_task_group::wait lançam quando uma tarefa filhos gera uma exceção, você não receberá um valor de retorno de eles.

Superior[]

Cancelando algoritmos paralelos

Algoritmos paralelos no PPL, por exemplo, parallel_for, compilação em grupos de trabalho.Como consequência, você pode usar muitas das mesmas técnicas cancelar um algoritmo paralelo.

Os exemplos a seguir ilustram várias maneiras para cancelar um algoritmo paralelo.

O exemplo a seguir usa a função de run_with_cancellation_token para chamar o algoritmo de parallel_for .A função de run_with_cancellation_token utiliza um token cancelar como um argumento e chama a função de trabalho de forma síncrona fornecida.Porque os algoritmos paralelos são compilados como as tarefas, herda o símbolo de cancelamento de tarefa pai.Como consequência, parallel_for pode responder ao botão.

// 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
*/

O exemplo a seguir usa o método de concurrency::structured_task_group::run_and_wait para chamar o algoritmo de parallel_for .O método de structured_task_group::run_and_wait espera a tarefa fornecida concluir.O objeto de structured_task_group permite que a função de trabalho para cancelar a tarefa.

// 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;
}

O exemplo produz a seguinte saída.

  

O exemplo a seguir usa a manipulação de exceção para cancelar um loop de parallel_for .Os lê em tempo de execução a exceção para o contexto de chamada.

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;
}

O exemplo produz a seguinte saída.

  

O seguinte exemplo usa um sinalizador booleano para coordenar cancelamento em um loop de parallel_for .Cada tarefa é executada porque este exemplo não usar manipulação de método ou de exceção de cancel para cancelar o conjunto de aparência geral de tarefas.Como consequência, essa técnica pode ter uma sobrecarga computacional mais do que um mecanismo cancelar.

// 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.
   }
});

Cada método cancelar tem vantagens sobre as outras.Escolha o método que se adapta suas necessidades específicas.

Superior[]

Quando não usar o para cancelar

O uso de cancelamento é apropriado quando cada membro de um grupo de tarefas relacionadas pode deixar em tempo hábil.No entanto, há alguns cenários onde o botão não pode ser apropriado para seu aplicativo.Por exemplo, porque cancelamento de tarefa é cooperativo, o conjunto de aparência geral de tarefas não cancelará se qualquer tarefa individual é bloqueada.Por exemplo, se uma tarefa ainda não foi iniciado, mas ele desbloqueia outra tarefa ativa, ela não iniciará se o grupo de trabalho é cancelado.Isso pode fazer com que um deadlock ocorre no seu aplicativo.Um segundo exemplo de onde o uso de cancelamento não pode ser apropriada é quando uma tarefa é cancelado, mas sua tarefa filho executa uma operação importante, como liberar um recurso.Porque o conjunto de aparência geral de tarefas é cancelado quando a tarefa pai é cancelada, a operação não será executado.Para um exemplo que ilustra este ponto, consulte a seção de Entenda como o efeito de manipulação de exceção e cancelar a destruição objetos nas práticas recomendadas no tópico de biblioteca dos padrões de paralela.

Superior[]

Tópicos relacionados

Nome

Descrição

Como: Use o botão para interromper de um loop paralelo

Mostra como usar o botão para implementar um algoritmo de pesquisa paralela.

Como: Use manipulação de exceção para interromper de um loop paralelo

Mostra como usar a classe de task_group para escrever um algoritmo de pesquisa para um estrutura de árvore básica.

Manipulação de exceção em tempo de execução de concorrência

Descreve como o tempo de execução trata exceções que são geradas por grupos de trabalho, por tarefas leve, e agentes por assíncronas, e como responder às exceções em seus aplicativos.

Paralelismo de tarefa (tempo de execução de simultaneidade)

Descreve como tarefas se referem aos grupos de trabalho e como você pode usar tarefas estruturada e não estruturada em seus aplicativos.

Algoritmos paralelos

Descreve os algoritmos paralelos, executados simultaneamente o trabalho em coleções de dados

A modelos paralela a biblioteca (PPL)

Fornece uma visão geral de biblioteca dos padrões de paralela.

Referência

a classe (Runtime de simultaneidade) de tarefas.

cancellation_token_source classe

cancellation_token classe

classe de task_group

classe de structured_task_group

função de parallel_for