Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом документе рассматривается роль отмены в библиотеке параллельных шаблонов (PPL), а также объясняется, как отменить параллельную работу и как определить, что параллельная работа отменена.
Примечание.
Среда выполнения использует обработку исключений для реализации отмены. Не следует перехватывать или обрабатывать эти исключения в своем коде. Кроме того, рекомендуется писать безопасный в отношении исключений код в функциях для ваших задач. Например, можно использовать шаблон RAII (Инициализация — приобретение ресурсов), чтобы обеспечить правильную обработку ресурсов при возникновении исключения в теле задачи. Полный пример, использующий шаблон RAII для очистки ресурса в отменяемой задаче, см. в пошаговом руководстве. Удаление работы из потока пользовательского интерфейса.
Основные моменты
Отмена осуществляется совместно и предусматривает координацию между кодом, запрашивающим отмену, и задачей, которая отвечает на отмену.
Если возможно, используйте токены отмены, чтобы отменить работу. Класс concurrency::cancellation_token определяет маркер отмены.
При использовании маркеров отмены используйте метод конкурентности::cancellation_token_source::cancel, чтобы инициировать отмену, и функцию конкурентности::cancel_current_task для реагирования на отмену. Используйте метод параллелизма::cancellation_token::is_canceled, чтобы проверить, запрашивает ли любая другая задача отмены.
Отмена не происходит немедленно. Хотя новая работа не запущена, если задача или группа задач отменена, активная работа должна проверяться и реагировать на отмену.
Продолжение, зависящее от значения, наследует токен отмены предыдущей задачи. Продолжение на основе задачи никогда не наследует маркер от задачи-предшественника.
Используйте метод concurrency::cancellation_token::none при вызове конструктора или функции, принимающей
cancellation_tokenобъект, если вы не хотите, чтобы операция могла быть отменена. Кроме того, если маркер отмены не передается конструктору concurrency::task или функции concurrency::create_task, эта задача не может быть отменена.
В этом документе
Параллельные рабочие деревья
В PPL для управления детализированными задачами и вычислениями используются задачи и группы задач. Вы можете вложить группы задач для создания деревьев параллельной работы. На следующем рисунке показано дерево параллельной работы. На этом рисунке tg1 и tg2 представляют группы задач; t1, t2, t3, t4 и t5 представляют работы, которые выполняют группы задач.
В следующем примере показан код, который необходим для создания дерева на рисунке. В этом примере tg1 и tg2 — это объекты concurrency::structured_task_group; t1, t2, t3, t4, и t5 — это объекты 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();
}
Можно также использовать класс параллелизма::task_group для создания аналогичного дерева работы. Класс concurrency::task также поддерживает понятие дерева задач. Однако дерево task является деревом зависимостей. В дереве task следующие задания выполняются после текущих. В дереве группы задач внутренняя работа завершается до внешней работы. Дополнительные сведения о различиях между задачами и группами задач см. в разделе "Параллелизм задач".
[В начало]
Отмена параллельных задач
Существует несколько способов отмены параллельной работы. Предпочтительный способ — использование токена отмены. Группы задач также поддерживают методы concurrency::task_group::cancel и concurrency::structured_task_group::cancel. Еще один способ — создать исключение в теле рабочей функции задачи. Какой бы метод вы ни выбрали, нужно понимать, что отмена не происходит немедленно. Хотя новая работа не запущена, если задача или группа задач отменена, активная работа должна проверяться и реагировать на отмену.
Дополнительные примеры, которые отменяют параллельные задачи, см. в пошаговом руководстве по подключению с помощью задач и XML HTTP-запросов, руководстве, как использовать отмену для выхода из параллельного цикла, и руководстве, как использовать обработку исключений для выхода из параллельного цикла.
Использование маркера отмены для отмены параллельной работы
Классы task, task_group и structured_task_group поддерживают отмену посредством использования токенов отмены. PPL определяет классы concurrency::cancellation_token_source и concurrency::cancellation_token для этой цели. При использовании токена отмены, чтобы отменить работу, среда выполнения не запускает новую работу, которая подписывается на этот токен. Работа, которая уже активна, может использовать функцию-член is_canceled для отслеживания маркера отмены и останавливаться, когда это возможно.
Чтобы инициировать отмену, вызовите метод concurrency::cancellation_token_source::cancel. Вы можете ответить на отмену следующими способами.
Для
taskобъектов используйте функцию concurrency::cancel_current_task.cancel_current_taskотменяет текущую задачу и любые ее продолжения, зависящие от значений. (Он не отменяет токен отмены, связанный с задачей или ее продолжениями.)Для групп задач и параллельных алгоритмов используйте функцию concurrency::is_current_task_group_canceling для обнаружения отмены и выхода из тела задачи как можно скорее, когда эта функция возвращает
true. (Не вызывайтеcancel_current_taskиз группы задач.)
В следующем примере показан первый базовый шаблон для отмены задачи. Тело задачи время от времени проверяет, нет ли отмены внутри цикла.
// task-basic-cancellation.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <concrt.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 (token.is_canceled())
{
// 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 генерирует исключение, поэтому нет необходимости явно возвращаться из текущего цикла или функции.
Совет
Кроме того, вы можете вызвать функцию concurrency::interruption_point вместо cancel_current_task.
Необходимо вызвать cancel_current_task при реагировании на отмену, поскольку она переводит задачу в отмененное состояние. Если вы вернетесь раньше вместо вызова функции cancel_current_task, операция перейдет в состояние завершения, и будут выполнены все продолжения, зависящие от значений.
Внимание
Никогда не вызывайте исключение task_canceled в своем коде. Вместо него вызовите метод cancel_current_task.
Когда задача заканчивается в отмененном состоянии, метод concurrency::task::get вызывает concurrency::task_canceled. (И наоборот, concurrency::task::wait возвращает task_status::canceled и не вызывает исключения.) В следующем примере показано это поведение для продолжения на основе задач. Продолжение, основанное на задаче, вызывается всегда, даже если предшествующая задача отменена.
// 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.
*/
Поскольку продолжения на основе значений наследуют токен от своих предшествующих задач, если они не были созданы с явным токеном, продолжения сразу же переходят в состояние отмены, даже если предшествующая задача всё ещё выполняется. Поэтому любое исключение, выбрасываемое предшествующей задачей после отмены, не распространяется на задачи продолжения. Отмена всегда переопределяет состояние предшествующей задачи. Следующий пример похож на предыдущий, но показывает поведение продолжения, основанного на значении.
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.
*/
Внимание
Если маркер отмены не передается task конструктору или функции параллелизма::create_task , эта задача не может быть отменена. Кроме того необходимо передать один и тот же токен отмены конструктору всех вложенных задач (т. е. задач, которые создаются в теле другой задачи), чтобы отменить все задачи одновременно.
Может понадобиться выполнить собственный код, когда токен отмены отменен. Например, если пользователь нажимает кнопку "Отмена" в пользовательском интерфейсе, чтобы отменить операцию, можно отключить эту кнопку, пока пользователь не начнет другую операцию. В следующем примере показано, как использовать метод concurrency::cancellation_token::register_callback для регистрации функции обратного вызова, которая выполняется при отмене токена отмены.
// 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.
*/
Документ Параллелизм задач объясняет разницу между продолжениями, основанными на значениях, и продолжениями, основанными на задачах. Если не предоставить объект cancellation_token задаче продолжения, продолжение наследует токен отмены из предшествующей задачи следующими способами.
Продолжение, основанное на значении, всегда наследует токен отмены предшествующей задачи.
Продолжение на основе задач никогда не наследует токен отмены предшествующей задачи. Единственный способ сделать продолжение на основе задач отменяемым — явно передать токен отмены.
Эти поведения не изменяются из-за сбоя задачи (той, которая создает исключение). В этом случае отменяется континуирование на основе значений; континуирование на основе задач не отменяется.
Внимание
Задача, которая создается внутри другой задачи (вложенная задача), не наследует токен отмены от родительской задачи. Только продолжение, основанное на значении, наследует токен отмены своей предшествующей задачи.
Совет
Используйте метод concurrency::cancellation_token::none при вызове конструктора или функции, принимающей cancellation_token объект, если вы не хотите, чтобы операция могла быть отменена.
Также можно предоставить токен отмены конструктору объекта task_group или structured_task_group. Важным аспектом является то, что дочерние группы задач наследуют этот токен отмены. Пример, демонстрирующий эту концепцию с использованием функции concurrency::run_with_cancellation_token для вызова parallel_for, см. раздел "Отмена параллельных алгоритмов" далее в этом документе.
[В начало]
Токены отмены и композиция задач
Функции concurrency::when_all и concurrency::when_any могут помочь сочетать несколько задач для реализации общих паттернов. В этом разделе описывается, как эти функции работают с токенами отмены.
Если вы предоставляете функции маркер отмены when_allwhen_any, отмена произойдет только при аннулировании маркера или если одна из выполняемых задач завершится в отмененном состоянии или вызовет исключение.
Функция when_all наследует токен отмены от каждой задачи, формирующей общую операцию, если ей не предоставляется токен отмены. Задача, возвращаемая из when_all, отменяется при отмене любого из этих маркеров, если по крайней мере одна из задач участника еще не запущена или находится в процессе выполнения. Аналогичное поведение возникает, когда одна из задач выбрасывает исключение — задача, возвращаемая из when_all, немедленно отменяется с этим исключением.
Среда выполнения выбирает токен аннулирования для задачи, получаемой из функции when_any, когда эта задача завершена. Если ни одна из участвующих задач не заканчивается в завершенном состоянии или одна или более задач создают исключение, одна из создавших исключение задач выбирается для выполнения when_any, а ее токен выбирается как токен для окончательной задачи. Если более чем одна задача завершилась, то задача, возвращаемая из задачи when_any, также завершится. Среда выполнения пытается выбрать завершенную задачу, токен которой не отменяется во время завершения, чтобы задача, которая возвращается из when_any, не отменялась сразу же, даже если остальные выполняющиеся задачи могут завершиться позднее.
[В начало]
Использование метода отмены для отмены параллельной работы
Методы concurrency::task_group::cancel и concurrency::structured_task_group::cancel переводят группу задач в состояние отмены. После вызова метода cancel группа задач не начинает выполнение следующих задач. Методы cancel могут вызываться несколькими дочерними задачами. Отмененная задача приводит к тому, что методы concurrency::task_group::wait и concurrency::structured_task_group::wait возвращают concurrency::canceled.
Если группа задач отменена, вызовы от каждой дочерней задачи в среду выполнения могут активировать точку прерывания, что приводит к генерации и перехвату внутреннего исключения для канселлирования активных задач. Среда выполнения с параллелизмом не определяет конкретные точки прерывания; они могут возникать в любом вызове среды выполнения. Среда выполнения должна обрабатывать исключения, которые она вызывает, чтобы выполнить отмену. Поэтому не следует обрабатывать неизвестные исключения в теле задачи.
Если дочерняя задача выполняет длительную операцию и не взаимодействует со средой выполнения, она должна периодически проверять возможность отмены и завершаться своевременно. В следующем примере показывается один из способов определения, когда работа отменяется. Задача t4 отменяет родительскую группу задач при обнаружении ошибки. Задача t5 периодически вызывает метод structured_task_group::is_canceling для проверки отмены. Если родительская группа задач отменяется, задача t5 выводит сообщение и завершает работу.
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
// cancellation.
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();
В этом примере проверяется отмена на каждой 100-й итерации цикла задачи. Частота, с которой выполняется проверка отмены, зависит от объема работы, выполняемой вашей задачей, и того, насколько быстро требуется, чтобы задачи реагировали на отмену.
Если у вас нет доступа к объекту родительской группы задач, вызовите функцию параллелизма::is_current_task_group_canceling , чтобы определить, отменена ли родительская группа задач.
Метод cancel влияет только на дочерние задачи. Например, если отменить группу задач tg1, показанную на рисунке дерева параллельной работы, будут затронуты все задачи в дереве (t1, t2, t3, t4 и t5). Если отменить вложенную группу задач tg2, будут затронуты только задачи t4 и t5.
При вызове метода cancel будут также отменены все дочерние группы задач. Однако отмена не повлияет ни на какие родительские объекты группы задач в дереве параллельной работы. В следующих примерах это демонстрируется с опорой на иллюстрацию дерева параллельной работы.
В первом из этих примеров создается рабочая функция для задачи t4, которая является дочерним элементом группы задач tg2. Эта рабочая функция вызывает функцию work в цикле. Если какой-либо вызов функции или процедуры work завершается неудачно, задача отменяет родительскую группу задач. В результате группа задач tg2 переходит в отмененное состояние, но группа задач 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;
}
}
});
Второй пример аналогичен первому, но за тем исключением, что задача отменяет группу задач tg1. Это влияет на все задачи в дереве (t1, t2, t3, t4 и 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 не является потокобезопасным. Таким образом, дочерняя задача, которая вызывает метод своего родительского объекта structured_task_group, приводит к непредсказуемому поведению. Исключениями этого правила являются методы structured_task_group::cancel и concurrency::structured_task_group::is_canceling. Дочерняя задача может вызывать эти методы для отмены родительской группы задач и проверки на предмет отмены.
Внимание
Хотя можно использовать токен отмены, чтобы отменить работу, выполняемую группой задач, которая выполняется как дочерний элемент объекта task, невозможно использовать методы task_group::cancel или structured_task_group::cancel, чтобы отменить объекты task, выполняемые в группе задач.
[В начало]
Использование исключений для отмены параллельной работы
Использование токенов отмены и метода cancel более эффективно, чем обработка исключений при отмене дерева параллельной работы. Токены отмены и метод cancel отменяют задачу и все дочерние задачи в иерархическом порядке сверху вниз. И наоборот, обработка исключений работает в режиме «снизу вверх» и необходимо отменять каждую дочернюю группу задач независимо, поскольку исключение распространяется вверх. Раздел Обработка исключений объясняет, как среда выполнения параллельных задач использует исключения для передачи ошибок. Однако не все исключения указывают на ошибку. Например, алгоритм поиска может отменить связанную задачу при нахождении результата. Тем не менее, как упоминалось ранее, обработка исключений менее эффективна, чем использование метода cancel для отмены параллельной работы.
Внимание
Рекомендуется использовать исключения для отмены параллельной работы только при необходимости. Токены отмены и методы cancel группы задач более эффективны и менее подвержены возникновению ошибок.
Когда вы выбрасываете ошибку в теле рабочей функции, которая передается в группу задач, среда выполнения сохраняет эту ошибку и передает её в контекст, ожидающий завершения этой группы задач. Как и в случае использования метода cancel, среда выполнения удаляет любые задачи, которые еще не были запущены, и не принимает новые задачи.
Третий пример напоминает второй, за исключением того, что задача t4 создает исключение для отмены группы задач tg2. В этом примере блок try-catch используется для проверки отмены, когда группа задач tg2 ожидает завершения своих дочерних задач. Как и в первом примере, в результате группа задач tg2 переходит в отмененное состояние, но группа задач 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;
}
В четвертом примере используется обработка исключений для отмены всего дерева работы. В этом примере исключение перехватывается, когда группа задач tg1 ожидает завершения своих дочерних задач, а не когда группа задач tg2 ожидает своих дочерних задач. Как и во втором примере, это приводит к переходу в отмененное состояние обеих групп задач в дереве, tg1 и tg2.
// 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;
}
Так как методы task_group::wait и structured_task_group::wait вызываются, когда дочерняя задача создает исключение, вы не получите от них возвращаемое значение.
[В начало]
Отмена параллельных алгоритмов
Параллельные алгоритмы в PPL (например, parallel_for) основаны на группах задач. Таким образом, многие из тех же способов можно использовать для для отмены параллельного алгоритма.
Следующие примеры иллюстрируют несколько способов отмены параллельного алгоритма.
В следующем примере функция run_with_cancellation_token используется для вызова алгоритма parallel_for. Функция run_with_cancellation_token принимает в качестве аргумента токен отмены и одновременно вызывает предоставленную рабочую функцию. Поскольку параллельные алгоритмы строятся на задачах, они наследуют токен отмены родительской задачи. Поэтому parallel_for может реагировать на отмену.
// 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
*/
В следующем примере используется метод concurrency::structured_task_group::run_and_wait для вызова алгоритма parallel_for. Метод structured_task_group::run_and_wait ожидает завершения предоставленной задачи. Объект structured_task_group позволяет рабочей функции отменить задачу.
// To enable cancellation, 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;
}
В этом примере формируются следующие данные:
The task group status is: canceled.
В следующем примере используется обработка исключений для отмены цикла parallel_for. Среда выполнения маршалирует исключение в вызывающий контекст.
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;
}
В этом примере получается следующий результат.
Caught 50
В следующем примере используется булевский флаг для координации отмены в цикле parallel_for. Каждая задача выполняется, поскольку в этом примере не используется метод cancel или обработка исключений, чтобы отменить весь набор задач. Таким образом, этот метод может иметь больше вычислительных затрат, чем механизм отмены.
// Create a Boolean flag to coordinate cancellation.
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.
}
});
Каждый метод отмены имеет свои преимущества по сравнению с другими. Выбирайте метод, который соответствует вашим конкретным требованиям.
[В начало]
Когда не следует использовать отмену
Использование отмены подходит в тех случаях, когда каждый участник группы связанных задач может завершить свою работу своевременно. Однако существуют некоторые сценарии, в которых отмена может не подойти для вашего приложения. Например, поскольку отмена задач осуществляется совместно, весь набор задач не будет отменен, если одна из задач заблокирована. Например, если одна задача еще не запущена, но разблокирует другую активную задачу, эта задача не запустится, если отменяется группа задач. Это может вызвать взаимоблокировку в вашем приложении. Второй пример, когда использование отмены может не подойти: задача отменяется, но ее дочерняя задача выполняет важную операцию, например высвобождение ресурса. Так как при отмене родительской задачи отменяется весь набор задач, эта операция не будет выполнена. Пример, иллюстрирующий этот момент, см. в разделе "Понимание того, как отмена и обработка исключений влияют на уничтожение объектов" в теме "Рекомендации по библиотеке параллельных шаблонов."
[В начало]
Связанные темы
| Заголовок | Описание |
|---|---|
| Как использовать отмену для выхода из параллельного цикла | Показывается, как использовать отмену для реализации алгоритма параллельного поиска. |
| Практическое руководство. Использование обработки исключений для выхода из параллельного цикла | Здесь приводятся способы использования класса task_group для записи алгоритма поиска для базовой структуры дерева. |
| Обработка исключений | В этом разделе описывается обработка в среде выполнения исключений, созданных группами задач, упрощенными задачами и асинхронными агентами, а также способы реагирования на исключения в приложениях. |
| Параллелизм задач | В этом разделе описывается, как задачи связаны с группами задач и как можно использовать структурированные и неструктурированные задачи в приложениях. |
| Параллельные алгоритмы | В этом разделе описываются параллельные алгоритмы, одновременно выполняющие работу с коллекциями данных. |
| Библиотека параллельных шаблонов | Предоставляется обзор библиотеки шаблонов параллелизма. |
Справочные материалы
Класс task (среда выполнения с параллелизмом)