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çã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.
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.
Usando 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:
Para objetos de task , use as funções de concurrency::is_task_cancellation_requested e de concurrency::cancel_current_task .cancel_current_task cancela a tarefa atual e qualquer um das continuações valor com base.(Desfizer o símbolo cancelar que está associado com a tarefa ou suas continuações.)
Para grupos de trabalho e algoritmos paralelos, use a função de concurrency::is_current_task_group_canceling para detectar o botão e retornar o mais rápido possível do corpo da tarefa quando essa função retorna true.(Não chamar cancel_current_task de um grupo de trabalho.)
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.
Dica |
---|
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.
Cuidado |
---|
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.
*/
Cuidado |
---|
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.
Cuidado |
---|
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. |
Dica |
---|
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[]
Tokens 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[]
Usando 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.
Cuidado |
---|
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[]
Usando 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.
Cuidado |
---|
É 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 |
---|---|
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. |
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. |
|
Descreve como tarefas se referem aos grupos de trabalho e como você pode usar tarefas estruturada e não estruturada em seus aplicativos. |
|
Descreve os algoritmos paralelos, executados simultaneamente o trabalho em coleções de dados |
|
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