Criando operações assíncronas em C++ para aplicativos UWPCreating Asynchronous Operations in C++ for UWP Apps

Este documento descreve alguns dos principais pontos a serem considerados quando você usa a classe Task para produzir operações assíncronas baseadas em ThreadPool do Windows em um aplicativo UWP (Universal Windows Runtime).This document describes some of the key points to keep in mind when you use the task class to produce Windows ThreadPool-based asynchronous operations in a Universal Windows Runtime (UWP) app.

O uso da programação assíncrona é um componente fundamental do modelo de aplicativo Windows Runtime porque permite que os aplicativos permaneçam responsivos à entrada do usuário.The use of asynchronous programming is a key component in the Windows Runtime app model because it enables apps to remain responsive to user input. Você pode iniciar uma tarefa de execução longa sem bloquear o thread da interface do usuário e pode receber os resultados da tarefa mais tarde.You can start a long-running task without blocking the UI thread, and you can receive the results of the task later. Você também pode cancelar tarefas e receber notificações de progresso conforme as tarefas são executadas em segundo plano.You can also cancel tasks and receive progress notifications as tasks run in the background. O documento programação assíncrona em C++ fornece uma visão geral do padrão assíncrono que está disponível no Visual C++ para criar aplicativos UWP.The document Asynchronous programming in C++ provides an overview of the asynchronous pattern that's available in Visual C++ to create UWP apps. Esse documento ensina como consumir e criar cadeias de operações de Windows Runtime assíncronas.That document teaches how to both consume and create chains of asynchronous Windows Runtime operations. Esta seção descreve como usar os tipos em ppltasks. h para produzir operações assíncronas que podem ser consumidas por outro componente Windows Runtime e como controlar como o trabalho assíncrono é executado.This section describes how to use the types in ppltasks.h to produce asynchronous operations that can be consumed by another Windows Runtime component and how to control how asynchronous work is executed. Considere também a leitura de padrões de programação assíncrona e dicas em Hilo (aplicativos da Windows Store usando C++ e XAML) para saber como usamos a classe Task para implementar operações assíncronas no hilo, um aplicativo Windows Runtime usando C++ e XAML.Also consider reading Async programming patterns and tips in Hilo (Windows Store apps using C++ and XAML) to learn how we used the task class to implement asynchronous operations in Hilo, a Windows Runtime app using C++ and XAML.

Observação

Você pode usar a PPL ( biblioteca de padrões paralelos ) e a biblioteca de agentes assíncronos em um aplicativo UWP.You can use the Parallel Patterns Library (PPL) and Asynchronous Agents Library in a UWP app. No entanto, você não pode usar o Agendador de Tarefas ou o Gerenciador de recursos.However, you cannot use the Task Scheduler or the Resource Manager. Este documento descreve os recursos adicionais que a PPL fornece que estão disponíveis apenas para um aplicativo UWP, e não para um aplicativo de desktop.This document describes additional features that the PPL provides that are available only to a UWP app, and not to a desktop app.

Pontos-chaveKey points

  • Use Concurrency:: create_async para criar operações assíncronas que podem ser usadas por outros componentes (que podem ser escritos em linguagens diferentes de C++).Use concurrency::create_async to create asynchronous operations that can be used by other components (which might be written in languages other than C++).

  • Use Concurrency::p rogress_reporter para relatar notificações de progresso para componentes que chamam suas operações assíncronas.Use concurrency::progress_reporter to report progress notifications to components that call your asynchronous operations.

  • Use tokens de cancelamento para permitir que operações assíncronas internas sejam canceladas.Use cancellation tokens to enable internal asynchronous operations to cancel.

  • O comportamento da create_async função depende do tipo de retorno da função de trabalho que é passada para ele.The behavior of the create_async function depends on the return type of the work function that is passed to it. Uma função de trabalho que retorna uma tarefa ( task<T> ou task<void> ) é executada de forma síncrona no contexto que chamou create_async .A work function that returns a task (either task<T> or task<void>) runs synchronously in the context that called create_async. Uma função de trabalho que retorna T ou void é executada em um contexto arbitrário.A work function that returns T or void runs in an arbitrary context.

  • Você pode usar o método Concurrency:: Task:: then para criar uma cadeia de tarefas que executa uma após a outra.You can use the concurrency::task::then method to create a chain of tasks that run one after another. Em um aplicativo UWP, o contexto padrão para as continuaçãos de uma tarefa depende de como essa tarefa foi construída.In a UWP app, the default context for a task's continuations depends on how that task was constructed. Se a tarefa foi criada passando uma ação assíncrona para o construtor da tarefa ou passando uma expressão lambda que retorna uma ação assíncrona, o contexto padrão para todas as continuaçãos dessa tarefa é o contexto atual.If the task was created by passing an asynchronous action to the task constructor, or by passing a lambda expression that returns an asynchronous action, then the default context for all continuations of that task is the current context. Se a tarefa não for construída a partir de uma ação assíncrona, um contexto arbitrário será usado por padrão para as continuaçãos da tarefa.If the task is not constructed from an asynchronous action, then an arbitrary context is used by default for the task's continuations. Você pode substituir o contexto padrão pela classe Concurrency:: task_continuation_context .You can override the default context with the concurrency::task_continuation_context class.

Neste documentoIn this document

Criando operações assíncronasCreating Asynchronous Operations

Você pode usar o modelo de tarefa e continuação na PPL (biblioteca de padrões paralelos) para definir tarefas em segundo plano, bem como tarefas adicionais que são executadas quando a tarefa anterior é concluída.You can use the task and continuation model in the Parallel Patterns Library (PPL) to define background tasks as well as additional tasks that run when the previous task completes. Essa funcionalidade é fornecida pela classe Concurrency:: Task .This functionality is provided by the concurrency::task class. Para obter mais informações sobre esse modelo e a task classe, consulte paralelismo de tarefas.For more information about this model and the task class, see Task Parallelism.

O Windows Runtime é uma interface de programação que você pode usar para criar aplicativos UWP que são executados somente em um ambiente de sistema operacional especial.The Windows Runtime is a programming interface that you can use to create UWP apps that run only in a special operating system environment. Esses aplicativos usam funções autorizadas, tipos de dados e dispositivos e são distribuídos do Microsoft Store.Such apps use authorized functions, data types, and devices, and are distributed from the Microsoft Store. O Windows Runtime é representado pela Abi ( interface binária do aplicativo ).The Windows Runtime is represented by the Application Binary Interface (ABI). A ABI é um contrato binário subjacente que torna Windows Runtime APIs disponíveis para linguagens de programação, como Visual C++.The ABI is an underlying binary contract that makes Windows Runtime APIs available to programming languages such as Visual C++.

Usando o Windows Runtime, você pode usar os melhores recursos de várias linguagens de programação e combiná-los em um único aplicativo.By using the Windows Runtime, you can use the best features of various programming languages and combine them into one app. Por exemplo, você pode criar sua interface do usuário em JavaScript e executar a lógica de aplicativo computacionalmente intensiva em um componente do C++.For example, you might create your UI in JavaScript and perform the computationally-intensive app logic in a C++ component. A capacidade de executar essas operações computacionalmente intensivas em segundo plano é um fator fundamental para manter sua interface do usuário responsiva.The ability to perform these computationally-intensive operations in the background is a key factor in keeping your UI responsive. Como a task classe é específica do C++, você deve usar uma interface Windows Runtime para comunicar operações assíncronas com outros componentes (que podem ser escritos em linguagens diferentes de C++).Because the task class is specific to C++, you must use a Windows Runtime interface to communicate asynchronous operations to other components (which might be written in languages other than C++). O Windows Runtime fornece quatro interfaces que você pode usar para representar operações assíncronas:The Windows Runtime provides four interfaces that you can use to represent asynchronous operations:

Windows:: Foundation:: IAsyncActionWindows::Foundation::IAsyncAction
Representa uma ação assíncrona.Represents an asynchronous action.

Windows:: Foundation:: IAsyncActionWithProgress<TProgress>Windows::Foundation::IAsyncActionWithProgress<TProgress>
Representa uma ação assíncrona que relata o progresso.Represents an asynchronous action that reports progress.

Windows:: Foundation:: IAsyncOperation<TResult>Windows::Foundation::IAsyncOperation<TResult>
Representa uma operação assíncrona que retorna um resultado.Represents an asynchronous operation that returns a result.

Windows:: Foundation:: IAsyncOperationWithProgress<TResult, TProgress>Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress>
Representa uma operação assíncrona que retorna um resultado e relata o progresso.Represents an asynchronous operation that returns a result and reports progress.

A noção de uma ação significa que a tarefa assíncrona não produz um valor (imagine uma função que retorna void ).The notion of an action means that the asynchronous task doesn't produce a value (think of a function that returns void). A noção de uma operação significa que a tarefa assíncrona produz um valor.The notion of an operation means that the asynchronous task does produce a value. A noção de progresso significa que a tarefa pode relatar mensagens de progresso ao chamador.The notion of progress means that the task can report progress messages to the caller. O JavaScript, o .NET Framework e o Visual C++ fornece a sua própria maneira de criar instâncias dessas interfaces para uso no limite da ABI.JavaScript, the .NET Framework, and Visual C++ each provides its own way to create instances of these interfaces for use across the ABI boundary. Por Visual C++, a PPL fornece a função Concurrency:: create_async .For Visual C++, the PPL provides the concurrency::create_async function. Essa função cria uma ação ou operação assíncrona Windows Runtime que representa a conclusão de uma tarefa.This function creates a Windows Runtime asynchronous action or operation that represents the completion of a task. A create_async função usa uma função de trabalho (normalmente uma expressão lambda), cria internamente um task objeto e encapsula essa tarefa em uma das quatro interfaces de Windows Runtime assíncronas.The create_async function takes a work function (typically a lambda expression), internally creates a task object, and wraps that task in one of the four asynchronous Windows Runtime interfaces.

Observação

Use create_async somente quando precisar criar uma funcionalidade que possa ser acessada de outro idioma ou outro componente Windows Runtime.Use create_async only when you have to create functionality that can be accessed from another language or another Windows Runtime component. Use a task classe diretamente quando souber que a operação é produzida e consumida pelo código C++ no mesmo componente.Use the task class directly when you know that the operation is both produced and consumed by C++ code in the same component.

O tipo de retorno de create_async é determinado pelo tipo de seus argumentos.The return type of create_async is determined by the type of its arguments. Por exemplo, se sua função de trabalho não retornar um valor e não relatar o progresso, o create_async retornará IAsyncAction .For example, if your work function doesn't return a value and doesn't report progress, create_async returns IAsyncAction. Se sua função de trabalho não retornar um valor e também relatar o progresso, o create_async retornará IAsyncActionWithProgress .If your work function doesn't return a value and also reports progress, create_async returns IAsyncActionWithProgress. Para relatar o progresso, forneça um objeto Concurrency::p rogress_reporter como o parâmetro para sua função de trabalho.To report progress, provide a concurrency::progress_reporter object as the parameter to your work function. A capacidade de relatar o progresso permite que você relate qual quantidade de trabalho foi executada e que valor ainda resta (por exemplo, como uma porcentagem).The ability to report progress enables you to report what amount of work was performed and what amount still remains (for example, as a percentage). Ele também permite que você relate os resultados conforme eles ficam disponíveis.It also enables you to report results as they become available.

As interfaces IAsyncAction, IAsyncActionWithProgress<TProgress>, IAsyncOperation<TResult> e IAsyncActionOperationWithProgress<TProgress, TProgress> fornecem um método Cancel que permite cancelar a operação assíncrona.The IAsyncAction, IAsyncActionWithProgress<TProgress>, IAsyncOperation<TResult>, and IAsyncActionOperationWithProgress<TProgress, TProgress> interfaces each provide a Cancel method that enables you to cancel the asynchronous operation. A task classe funciona com tokens de cancelamento.The task class works with cancellation tokens. Quando você usa um token de cancelamento para cancelar o trabalho, o tempo de execução não inicia um novo trabalho que assina esse token.When you use a cancellation token to cancel work, the runtime does not start new work that subscribes to that token. O trabalho que já está ativo pode monitorar seu token de cancelamento e parar quando puder.Work that is already active can monitor its cancellation token and stop when it can. Esse mecanismo é descrito mais detalhadamente no cancelamento do documento na ppl.This mechanism is described in greater detail in the document Cancellation in the PPL. Você pode conectar o cancelamento de tarefa com os métodos de Windows Runtime Cancel de duas maneiras.You can connect task cancellation with the Windows RuntimeCancel methods in two ways. Primeiro, você pode definir a função de trabalho que você passa para create_async para pegar um objeto Concurrency:: cancellation_token .First, you can define the work function that you pass to create_async to take a concurrency::cancellation_token object. Quando o Cancel método é chamado, esse token de cancelamento é cancelado e as regras normais de cancelamento se aplicam ao task objeto subjacente que dá suporte à create_async chamada.When the Cancel method is called, this cancellation token is canceled and the normal cancellation rules apply to the underlying task object that supports the create_async call. Se você não fornecer um objeto cancellation_token, o objeto task subjacente define um de forma implícita.If you do not provide a cancellation_token object, the underlying task object defines one implicitly. Defina um objeto cancellation_token quando você precisa responder de forma cooperativa ao cancelamento na sua função de trabalho.Define a cancellation_token object when you need to cooperatively respond to cancellation in your work function. O exemplo de seção : controlando a execução em um aplicativo Windows Runtime com C++ e XAML mostra um exemplo de como executar o cancelamento em um aplicativo de plataforma universal do Windows (UWP) com C# e XAML que usa um componente personalizado do Windows Runtime C++.The section Example: Controlling Execution in a Windows Runtime App with C++ and XAML shows an example of how to perform cancellation in a Universal Windows Platform (UWP) app with C# and XAML that uses a custom Windows Runtime C++ component.

Aviso

Em uma cadeia de continuaçãos de tarefa, sempre Limpe o estado e, em seguida, chame Concurrency:: cancel_current_task quando o token de cancelamento for cancelado.In a chain of task continuations, always clean up state and then call concurrency::cancel_current_task when the cancellation token is canceled. Se você retornar antecipadamente em vez de chamar cancel_current_task , a operação passará para o estado concluído em vez do estado cancelado.If you return early instead of calling cancel_current_task, the operation transitions to the completed state instead of the canceled state.

A tabela a seguir resume as combinações que você pode usar para definir operações assíncronas em seu aplicativo.The following table summarizes the combinations that you can use to define asynchronous operations in your app.

Para criar essa interface de Windows RuntimeTo create this Windows Runtime interface Retornar este tipo decreate_asyncReturn this type from create_async Passe esses tipos de parâmetro para sua função de trabalho para usar um token de cancelamento implícitoPass these parameter types to your work function to use an implicit cancellation token Passe esses tipos de parâmetro para sua função de trabalho para usar um token de cancelamento explícitoPass these parameter types to your work function to use an explicit cancellation token
IAsyncAction void ortask<void>void or task<void> (nenhum)(none) (cancellation_token)(cancellation_token)
IAsyncActionWithProgress<TProgress> void ortask<void>void or task<void> (progress_reporter)(progress_reporter) (progress_reporter, cancellation_token)(progress_reporter, cancellation_token)
IAsyncOperation<TResult> T ou task<T>T or task<T> (nenhum)(none) (cancellation_token)(cancellation_token)
IAsyncActionOperationWithProgress<TProgress, TProgress> T ou task<T>T or task<T> (progress_reporter)(progress_reporter) (progress_reporter, cancellation_token)(progress_reporter, cancellation_token)

Você pode retornar um valor ou um task objeto da função de trabalho que você passa para a create_async função.You can return a value or a task object from the work function that you pass to the create_async function. Essas variações produzem comportamentos diferentes.These variations produce different behaviors. Quando você retorna um valor, a função de trabalho é encapsulada em um task para que possa ser executada em um thread em segundo plano.When you return a value, the work function is wrapped in a task so that it can be run on a background thread. Além disso, o subjacente task usa um token de cancelamento implícito.In addition, the underlying task uses an implicit cancellation token. Por outro lado, se você retornar um task objeto, a função de trabalho será executada de forma síncrona.Conversely, if you return a task object, the work function runs synchronously. Portanto, se você retornar um task objeto, certifique-se de que as operações demoradas em sua função de trabalho também sejam executadas como tarefas para permitir que seu aplicativo permaneça responsivo.Therefore, if you return a task object, ensure that any lengthy operations in your work function also run as tasks to enable your app to remain responsive. Além disso, o subjacente não task usa um token de cancelamento implícito.In addition, the underlying task does not use an implicit cancellation token. Portanto, você precisa definir sua função de trabalho para obter um cancellation_token objeto se precisar de suporte para cancelamento quando retornar um task objeto de create_async .Therefore, you need to define your work function to take a cancellation_token object if you require support for cancellation when you return a task object from create_async.

O exemplo a seguir mostra as várias maneiras de criar um IAsyncAction objeto que pode ser consumido por outro componente Windows Runtime.The following example shows the various ways to create an IAsyncAction object that can be consumed by another Windows Runtime component.

// Creates an IAsyncAction object and uses an implicit cancellation token.
auto op1 = create_async([]
{
    // Define work here.
});

// Creates an IAsyncAction object and uses no cancellation token.
auto op2 = create_async([]
{
    return create_task([]
    {
        // Define work here.
    });
});

// Creates an IAsyncAction object and uses an explicit cancellation token.
auto op3 = create_async([](cancellation_token ct)
{
    // Define work here.
});

// Creates an IAsyncAction object that runs another task and also uses an explicit cancellation token.
auto op4 = create_async([](cancellation_token ct)
{
    return create_task([ct]()
    {
        // Define work here.
    });
});

Exemplo: Criando um componente de Windows Runtime C++ e consumindo-o a partir de C#Example: Creating a C++ Windows Runtime Component and Consuming it from C#

Considere um aplicativo que usa XAML e C# para definir a interface do usuário e um componente Windows Runtime do C++ para executar operações de computação intensiva.Consider an app that uses XAML and C# to define the UI and a C++ Windows Runtime component to perform compute-intensive operations. Neste exemplo, o componente C++ computa quais números em um determinado intervalo são primos.In this example, the C++ component computes which numbers in a given range are prime. Para ilustrar as diferenças entre as quatro Windows Runtime interfaces de tarefa assíncronas, comece, no Visual Studio, criando uma solução em branco e nomeando-a Primes .To illustrate the differences among the four Windows Runtime asynchronous task interfaces, start, in Visual Studio, by creating a Blank Solution and naming it Primes. Em seguida, adicione à solução um projeto de componente Windows Runtime e nomeá-lo PrimesLibrary .Then add to the solution a Windows Runtime Component project and naming it PrimesLibrary. Adicione o código a seguir ao arquivo de cabeçalho C++ gerado (Este exemplo renomeia Class1. h para Primes. h).Add the following code to the generated C++ header file (this example renames Class1.h to Primes.h). Cada public método define uma das quatro interfaces assíncronas.Each public method defines one of the four asynchronous interfaces. Os métodos que retornam um valor retornam um objeto Windows:: Foundation:: Collections <int> :: IVector .The methods that return a value return a Windows::Foundation::Collections::IVector<int> object. Os métodos que relatam o progresso produzem double valores que definem a porcentagem de trabalho geral que foi concluída.The methods that report progress produce double values that define the percentage of overall work that has completed.

#pragma once

namespace PrimesLibrary
{
    public ref class Primes sealed
    {
    public:
        Primes();

        // Computes the numbers that are prime in the provided range and stores them in an internal variable.
        Windows::Foundation::IAsyncAction^ ComputePrimesAsync(int first, int last);

        // Computes the numbers that are prime in the provided range and stores them in an internal variable.
        // This version also reports progress messages.
        Windows::Foundation::IAsyncActionWithProgress<double>^ ComputePrimesWithProgressAsync(int first, int last);

        // Gets the numbers that are prime in the provided range.
        Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IVector<int>^>^ GetPrimesAsync(int first, int last);

        // Gets the numbers that are prime in the provided range. This version also reports progress messages.
        Windows::Foundation::IAsyncOperationWithProgress<Windows::Foundation::Collections::IVector<int>^, double>^ GetPrimesWithProgressAsync(int first, int last);
    };
}

Observação

Por convenção, os nomes de métodos assíncronos na Windows Runtime normalmente terminam com "Async".By convention, asynchronous method names in the Windows Runtime typically end with "Async".

Adicione o código a seguir ao arquivo de origem C++ gerado (Este exemplo renomeia Class1. cpp como Primes. cpp).Add the following code to the generated C++ source file (this example renames Class1.cpp to Primes.cpp). A is_prime função determina se sua entrada é primo.The is_prime function determines whether its input is prime. Os métodos restantes implementam a Primes classe.The remaining methods implement the Primes class. Cada chamada para create_async usa uma assinatura que é compatível com o método do qual ele é chamado.Each call to create_async uses a signature that's compatible with the method from which it is called. Por exemplo, como Primes::ComputePrimesAsync retorna IAsyncAction , a função de trabalho fornecida para create_async não retorna um valor e não pega um progress_reporter objeto como seu parâmetro.For example, because Primes::ComputePrimesAsync returns IAsyncAction, the work function that's provided to create_async doesn't return a value and doesn't take a progress_reporter object as its parameter.

// PrimesLibrary.cpp
#include "pch.h"
#include "Primes.h"
#include <atomic>
#include <collection.h>
#include <ppltasks.h>
#include <concurrent_vector.h>

using namespace concurrency;
using namespace std;

using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;

using namespace PrimesLibrary;

Primes::Primes()
{
}

// Determines whether the input value is prime. 
bool is_prime(int n)
{
    if (n < 2)
    {
        return false;
    }
    for (int i = 2; i < n; ++i)
    {
        if ((n % i) == 0)
        {
            return false;
        }
    }
    return true;
}

// Adds the numbers that are prime in the provided range  
// to the primes global variable.
IAsyncAction^ Primes::ComputePrimesAsync(int first, int last)
{
    return create_async([this, first, last]
    {
        // Ensure that the input values are in range. 
        if (first < 0 || last < 0)
        {
            throw ref new InvalidArgumentException();
        }
        // Perform the computation in parallel.
        parallel_for(first, last + 1, [this](int n)
        {
            if (is_prime(n))
            {
                // Perhaps store the value somewhere...
            }
        });
    });
}

IAsyncActionWithProgress<double>^ Primes::ComputePrimesWithProgressAsync(int first, int last)
{
    return create_async([first, last](progress_reporter<double> reporter)
    {
        // Ensure that the input values are in range.
        if (first < 0 || last < 0)
        {
            throw ref new InvalidArgumentException();
        }
        // Perform the computation in parallel. 
        atomic<long> operation = 0;
        long range = last - first + 1;
        double lastPercent = 0.0;
        parallel_for(first, last + 1, [&operation, range, &lastPercent, reporter](int n)
        {
            // Report progress message.
            double progress = 100.0 * (++operation) / range;
            if (progress >= lastPercent)
            {
                reporter.report(progress);
                lastPercent += 1.0;
            }

            if (is_prime(n))
            {
                // Perhaps store the value somewhere...
            }
        });
        reporter.report(100.0);
    });
}

IAsyncOperation<IVector<int>^>^ Primes::GetPrimesAsync(int first, int last)
{
    return create_async([this, first, last]() -> IVector<int>^
    {
        // Ensure that the input values are in range. 
        if (first < 0 || last < 0)
        {
            throw ref new InvalidArgumentException();
        }
        // Perform the computation in parallel.
        concurrent_vector<int> primes;
        parallel_for(first, last + 1, [this, &primes](int n)
        {
            // If the value is prime, add it to the global vector.
            if (is_prime(n))
            {
                primes.push_back(n);
            }
        });
        // Sort the results.
        sort(begin(primes), end(primes), less<int>());

        // Copy the results to an IVector object. The IVector 
        // interface makes collections of data available to other 
        // Windows Runtime components.
        auto results = ref new Vector<int>();
        for (int prime : primes)
        {
            results->Append(prime);
        }
        return results;
    });
}

IAsyncOperationWithProgress<IVector<int>^, double>^ Primes::GetPrimesWithProgressAsync(int first, int last)
{
    return create_async([this, first, last](progress_reporter<double> reporter) -> IVector<int>^
    {
        // Ensure that the input values are in range.
        if (first < 0 || last < 0)
        {
            throw ref new InvalidArgumentException();
        }
        // Perform the computation in parallel.
        concurrent_vector<int> primes;
        long operation = 0;
        long range = last - first + 1;
        double lastPercent = 0.0;
        parallel_for(first, last + 1, [&primes, &operation, range, &lastPercent, reporter](int n)
        {
            // Report progress message.
            double progress = 100.0 * (++operation) / range;
            if (progress >= lastPercent)
            {
                reporter.report(progress);
                lastPercent += 1.0;
            }

            // If the value is prime, add it to the local vector. 
            if (is_prime(n))
            {
                primes.push_back(n);
            }
        });
        reporter.report(100.0);

        // Sort the results.
        sort(begin(primes), end(primes), less<int>());

        // Copy the results to an IVector object. The IVector 
        // interface makes collections of data available to other 
        // Windows Runtime components.
        auto results = ref new Vector<int>();
        for (int prime : primes)
        {
            results->Append(prime);
        }
        return results;
    });
}

Primeiro, cada método executa a validação para garantir que os parâmetros de entrada sejam não negativos.Each method first performs validation to ensure that the input parameters are non-negative. Se um valor de entrada for negativo, o método lançará Platform:: InvalidArgumentException.If an input value is negative, the method throws Platform::InvalidArgumentException. O tratamento de erros é explicado mais adiante nesta seção.Error handling is explained later in this section.

Para consumir esses métodos de um aplicativo UWP, use o modelo de aplicativo em branco do Visual C# (XAML) para adicionar um segundo projeto à solução do Visual Studio.To consume these methods from a UWP app, use the Visual C# Blank App (XAML) template to add a second project to the Visual Studio solution. Este exemplo nomeia o projeto Primes .This example names the project Primes. Em seguida, no Primes projeto, adicione uma referência ao PrimesLibrary projeto.Then, from the Primes project, add a reference to the PrimesLibrary project.

Adicione o código a seguir a MainPage. XAML.Add the following code to MainPage.xaml. Esse código define a interface do usuário para que você possa chamar o componente C++ e exibir resultados.This code defines the UI so that you can call the C++ component and display results.

<Page
    x:Class="Primes.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Primes"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="300"/>
            <ColumnDefinition Width="300"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="125"/>
            <RowDefinition Height="125"/>
            <RowDefinition Height="125"/>
        </Grid.RowDefinitions>

        <StackPanel Grid.Column="0" Grid.Row="0">
            <Button Name="b1" Click="computePrimes">Compute Primes</Button>
            <TextBlock Name="tb1"></TextBlock>
        </StackPanel>

        <StackPanel Grid.Column="1" Grid.Row="0">
            <Button Name="b2" Click="computePrimesWithProgress">Compute Primes with Progress</Button>
            <ProgressBar Name="pb1" HorizontalAlignment="Left" Width="100"></ProgressBar>
            <TextBlock Name="tb2"></TextBlock>
        </StackPanel>

        <StackPanel Grid.Column="0" Grid.Row="1">
            <Button Name="b3" Click="getPrimes">Get Primes</Button>
            <TextBlock Name="tb3"></TextBlock>
        </StackPanel>

        <StackPanel Grid.Column="1" Grid.Row="1">
            <Button Name="b4" Click="getPrimesWithProgress">Get Primes with Progress</Button>
            <ProgressBar Name="pb4"  HorizontalAlignment="Left" Width="100"></ProgressBar>
            <TextBlock Name="tb4"></TextBlock>
        </StackPanel>

        <StackPanel Grid.Column="0" Grid.Row="2">
            <Button Name="b5" Click="getPrimesHandleErrors">Get Primes and Handle Errors</Button>
            <ProgressBar Name="pb5"  HorizontalAlignment="Left" Width="100"></ProgressBar>
            <TextBlock Name="tb5"></TextBlock>
        </StackPanel>

        <StackPanel Grid.Column="1" Grid.Row="2">
            <Button Name="b6" Click="getPrimesCancellation">Get Primes with Cancellation</Button>
            <Button Name="cancelButton" Click="cancelGetPrimes" IsEnabled="false">Cancel</Button>
            <ProgressBar Name="pb6"  HorizontalAlignment="Left" Width="100"></ProgressBar>
            <TextBlock Name="tb6"></TextBlock>
        </StackPanel>
    </Grid>
</Page>

Adicione o código a seguir à MainPage classe em MainPage. XAML.Add the following code to the MainPage class in MainPage.xaml. Esse código define um Primes objeto e os manipuladores de eventos de botão.This code defines a Primes object and the button event handlers.

private PrimesLibrary.Primes primesLib = new PrimesLibrary.Primes();

private async void computePrimes(object sender, RoutedEventArgs e)
{
    b1.IsEnabled = false;
    tb1.Text = "Working...";

    var asyncAction = primesLib.ComputePrimesAsync(0, 100000);

    await asyncAction;

    tb1.Text = "Done";
    b1.IsEnabled = true;
}

private async void computePrimesWithProgress(object sender, RoutedEventArgs e)
{
    b2.IsEnabled = false;
    tb2.Text = "Working...";

    var asyncAction = primesLib.ComputePrimesWithProgressAsync(0, 100000);
    asyncAction.Progress = new AsyncActionProgressHandler<double>((action, progress) =>
    {
        pb1.Value = progress;
    });

    await asyncAction;

    tb2.Text = "Done";
    b2.IsEnabled = true;
}

private async void getPrimes(object sender, RoutedEventArgs e)
{
    b3.IsEnabled = false;
    tb3.Text = "Working...";

    var asyncOperation = primesLib.GetPrimesAsync(0, 100000);

    await asyncOperation;

    tb3.Text = "Found " + asyncOperation.GetResults().Count + " primes";
    b3.IsEnabled = true;
}

private async void getPrimesWithProgress(object sender, RoutedEventArgs e)
{
    b4.IsEnabled = false;
    tb4.Text = "Working...";

    var asyncOperation = primesLib.GetPrimesWithProgressAsync(0, 100000);
    asyncOperation.Progress = new AsyncOperationProgressHandler<IList<int>, double>((operation, progress) =>
    {
        pb4.Value = progress;
    });

    await asyncOperation;

    tb4.Text = "Found " + asyncOperation.GetResults().Count + " primes";
    b4.IsEnabled = true;
}

private async void getPrimesHandleErrors(object sender, RoutedEventArgs e)
{
    b5.IsEnabled = false;
    tb5.Text = "Working...";

    var asyncOperation = primesLib.GetPrimesWithProgressAsync(-1000, 100000);
    asyncOperation.Progress = new AsyncOperationProgressHandler<IList<int>, double>((operation, progress) =>
    {
        pb5.Value = progress;
    });

    try
    {
        await asyncOperation;
        tb5.Text = "Found " + asyncOperation.GetResults().Count + " primes";
    }
    catch (ArgumentException ex)
    {
        tb5.Text = "ERROR: " + ex.Message;
    }

    b5.IsEnabled = true;
}

private IAsyncOperationWithProgress<IList<int>, double> asyncCancelableOperation;

private async void getPrimesCancellation(object sender, RoutedEventArgs e)
{
    b6.IsEnabled = false;
    cancelButton.IsEnabled = true;
    tb6.Text = "Working...";

    asyncCancelableOperation = primesLib.GetPrimesWithProgressAsync(0, 200000);
    asyncCancelableOperation.Progress = new AsyncOperationProgressHandler<IList<int>, double>((operation, progress) =>
    {
        pb6.Value = progress;
    });

    try
    {
        await asyncCancelableOperation;
        tb6.Text = "Found " + asyncCancelableOperation.GetResults().Count + " primes";
    }
    catch (System.Threading.Tasks.TaskCanceledException)
    {
        tb6.Text = "Operation canceled";
    }

    b6.IsEnabled = true;
    cancelButton.IsEnabled = false;
}

private void cancelGetPrimes(object sender, RoutedEventArgs e)
{
    cancelButton.IsEnabled = false;
    asyncCancelableOperation.Cancel();
}

Esses métodos usam as async await palavras-chave e para atualizar a interface do usuário após a conclusão das operações assíncronas.These methods use the async and await keywords to update the UI after the asynchronous operations complete. Para obter informações sobre codificação assíncrona em aplicativos UWP, consulte Threading e programação assíncrona.For information about asynchronous coding in UWP apps, see Threading and async programming.

Os getPrimesCancellation cancelGetPrimes métodos e funcionam em conjunto para permitir que o usuário cancele a operação.The getPrimesCancellation and cancelGetPrimes methods work together to enable the user to cancel the operation. Quando o usuário escolhe o botão Cancelar , o cancelGetPrimes método chama IAsyncOperationWithProgress <TResult, TProgress> :: Cancel para cancelar a operação.When the user chooses the Cancel button, the cancelGetPrimes method calls IAsyncOperationWithProgress<TResult, TProgress>::Cancel to cancel the operation. O Tempo de Execução de Simultaneidade, que gerencia a operação assíncrona subjacente, gera um tipo de exceção interna que é capturado pelo Windows Runtime para comunicar que o cancelamento foi concluído.The Concurrency Runtime, which manages the underlying asynchronous operation, throws an internal exception type that's caught by the Windows Runtime to communicate that cancellation has completed. Para obter mais informações sobre o modelo de cancelamento, consulte cancelamento.For more information about the cancellation model, see Cancellation.

Importante

Para permitir que a PPL relate corretamente ao Windows Runtime que cancelou a operação, não Capture esse tipo de exceção interna.To enable the PPL to correctly report to the Windows Runtime that it has canceled the operation, do not catch this internal exception type. Isso significa que você também não deve capturar todas as exceções ( catch (...) ).This means that you should also not catch all exceptions (catch (...)). Se você precisar capturar todas as exceções, relance a exceção para garantir que a Windows Runtime possa concluir a operação de cancelamento.If you must catch all exceptions, rethrow the exception to ensure that the Windows Runtime can complete the cancellation operation.

A ilustração a seguir mostra o Primes aplicativo após a escolha de cada opção.The following illustration shows the Primes app after each option has been chosen.

Windows Runtime aplicativo PrimesWindows Runtime Primes app

Para obter um exemplo que usa o create_async para criar tarefas assíncronas que podem ser consumidas por outras linguagens, consulte usando C++ na amostra do otimizador de viagens do Bing Maps.For an example that uses create_async to create asynchronous tasks that can be consumed by other languages, see Using C++ in the Bing Maps Trip Optimizer sample.

Controlando o thread de execuçãoControlling the Execution Thread

O Windows Runtime usa o modelo de Threading COM.The Windows Runtime uses the COM threading model. Nesse modelo, os objetos são hospedados em diferentes Apartments, dependendo de como eles lidam com sua sincronização.In this model, objects are hosted in different apartments, depending on how they handle their synchronization. Os objetos thread-safe são hospedados no MTA (multi-threaded apartment).Thread-safe objects are hosted in the multi-threaded apartment (MTA). Os objetos que devem ser acessados por um único thread são hospedados em um STA (single-threaded apartment).Objects that must be accessed by a single thread are hosted in a single-threaded apartment (STA).

Em um aplicativo que tem uma interface do usuário, o thread ASTA (Application STA) é responsável por bombear mensagens de janela e é o único thread no processo que pode atualizar os controles de interface do usuário hospedados no STA.In an app that has a UI, the ASTA (Application STA) thread is responsible for pumping window messages and is the only thread in the process that can update the STA-hosted UI controls. Isso tem duas conseqüências.This has two consequences. Primeiro, para permitir que o aplicativo permaneça responsivo, todas as operações de e/s intensivas de CPU não devem ser executadas no thread ASTA.First, to enable the app to remain responsive, all CPU-intensive and I/O operations should not be run on the ASTA thread. Segundo, os resultados provenientes de threads em segundo plano devem ser empacotados de volta para o ASTA para atualizar a interface do usuário.Second, results that come from background threads must be marshaled back to the ASTA to update the UI. Em um aplicativo UWP C++, MainPage todas as páginas XAML são executadas no ATSA.In a C++ UWP app, MainPage and other XAML pages all run on the ATSA. Portanto, as continuações de tarefa declaradas no ASTA são executadas lá por padrão para que você possa atualizar os controles diretamente no corpo de continuação.Therefore, task continuations that are declared on the ASTA are run there by default so you can update controls directly in the continuation body. No entanto, se você aninhar uma tarefa em outra tarefa, qualquer continuação nessa tarefa aninhada será executada no MTA.However, if you nest a task in another task, any continuations on that nested task run in the MTA. Portanto, você precisa considerar se deve especificar explicitamente em que contexto essas continuaçãos são executadas.Therefore, you need to consider whether to explicitly specify on what context these continuations run.

Uma tarefa que é criada a partir de uma operação assíncrona, como IAsyncOperation<TResult> , usa semântica especial que pode ajudá-lo a ignorar os detalhes de Threading.A task that's created from an asynchronous operation, such as IAsyncOperation<TResult>, uses special semantics that can help you ignore the threading details. Embora uma operação possa ser executada em um thread em segundo plano (ou pode não ser apoiada por um thread), suas continuações são, por padrão, garantidas de serem executadas no apartamento que iniciou as operações de continuação (em outras palavras, do apartamento que chamou task::then ).Although an operation might run on a background thread (or it may not be backed by a thread at all), its continuations are by default guaranteed to run on the apartment that started the continuation operations (in other words, from the apartment that called task::then). Você pode usar a classe Concurrency:: task_continuation_context para controlar o contexto de execução de uma continuação.You can use the concurrency::task_continuation_context class to control the execution context of a continuation. Use estes métodos auxiliares estáticos para criar task_continuation_context objetos:Use these static helper methods to create task_continuation_context objects:

Você pode passar um task_continuation_context objeto para o método Task:: then para controlar explicitamente o contexto de execução da continuação ou pode passar a tarefa para outro Apartment e, em seguida, chamar o task::then método para controlar implicitamente o contexto de execução.You can pass a task_continuation_context object to the task::then method to explicitly control the execution context of the continuation or you can pass the task to another apartment and then call the task::then method to implicitly control the execution context.

Importante

Como o thread da interface do usuário principal dos aplicativos UWP é executado sob STA, as continuações criadas nesse STA por padrão são executadas no STA.Because the main UI thread of UWP apps run under STA, continuations that you create on that STA by default run on the STA. Da mesma forma, as continuações criadas no MTA são executadas no MTA.Accordingly, continuations that you create on the MTA run on the MTA.

A seção a seguir mostra um aplicativo que lê um arquivo do disco, localiza as palavras mais comuns nesse arquivo e, em seguida, mostra os resultados na interface do usuário.The following section shows an app that reads a file from disk, finds the most common words in that file, and then shows the results in the UI. A operação final, atualizando a interface do usuário, ocorre no thread da interface do usuário.The final operation, updating the UI, occurs on the UI thread.

Importante

Esse comportamento é específico para aplicativos UWP.This behavior is specific to UWP apps. Para aplicativos da área de trabalho, você não controla onde as continuaçãos são executadas.For desktop apps, you do not control where continuations run. Em vez disso, o Agendador escolhe um thread de trabalho no qual executar cada continuação.Instead, the scheduler chooses a worker thread on which to run each continuation.

Importante

Não chamar Concurrency:: Task:: aguardar no corpo de uma continuação que é executada no Sta.Do not call concurrency::task::wait in the body of a continuation that runs on the STA. Caso contrário, o tempo de execução lançará Concurrency:: invalid_operation porque esse método bloqueia o thread atual e pode fazer com que o aplicativo fique sem resposta.Otherwise, the runtime throws concurrency::invalid_operation because this method blocks the current thread and can cause the app to become unresponsive. No entanto, você pode chamar o método Concurrency:: Task:: Get para receber o resultado da tarefa Antecedent em uma continuação baseada em tarefa.However, you can call the concurrency::task::get method to receive the result of the antecedent task in a task-based continuation.

Exemplo: controlando a execução em um aplicativo Windows Runtime com C++ e XAMLExample: Controlling Execution in a Windows Runtime App with C++ and XAML

Considere um aplicativo C++ XAML que lê um arquivo do disco, encontre as palavras mais comuns nesse arquivo e, em seguida, mostra os resultados na interface do usuário.Consider a C++ XAML app that reads a file from disk, finds the most common words in that file, and then shows the results in the UI. Para criar esse aplicativo, comece, no Visual Studio, criando um projeto de aplicativo em branco (universal do Windows) e nomeando-o CommonWords .To create this app, start, in Visual Studio, by creating a Blank App (Universal Windows) project and naming it CommonWords. No manifesto do aplicativo, especifique a capacidade da biblioteca de documentos para permitir que o aplicativo acesse a pasta documentos.In your app manifest, specify the Documents Library capability to enable the app to access the Documents folder. Além disso, adicione o tipo de arquivo Text (. txt) à seção declarações do manifesto do aplicativo.Also add the Text (.txt) file type to the declarations section of the app manifest. Para obter mais informações sobre as declarações e os recursos do aplicativo, consulte empacotamento, implantação e consulta de aplicativos do Windows.For more information about app capabilities and declarations, see Packaging, deployment, and query of Windows apps.

Atualize o Grid elemento em MainPage. XAML para incluir um ProgressRing elemento e um TextBlock elemento.Update the Grid element in MainPage.xaml to include a ProgressRing element and a TextBlock element. O ProgressRing indica que a operação está em andamento e TextBlock mostra os resultados da computação.The ProgressRing indicates that the operation is in progress and the TextBlock shows the results of the computation.

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <ProgressRing x:Name="Progress"/>
    <TextBlock x:Name="Results" FontSize="16"/>
</Grid>

Adicione as instruções a seguir #include a PCH. h.Add the following #include statements to pch.h.

#include <sstream>
#include <ppltasks.h>
#include <concurrent_unordered_map.h>

Adicione as seguintes declarações de método à MainPage classe (MainPage. h).Add the following method declarations to the MainPage class (MainPage.h).

private:
    // Splits the provided text string into individual words.
    concurrency::task<std::vector<std::wstring>> MakeWordList(Platform::String^ text);

    // Finds the most common words that are at least the provided minimum length.
    concurrency::task<std::vector<std::pair<std::wstring, size_t>>> FindCommonWords(const std::vector<std::wstring>& words, size_t min_length, size_t count);

    // Shows the most common words on the UI.
    void ShowResults(const std::vector<std::pair<std::wstring, size_t>>& commonWords);

Adicione as instruções a seguir using a MainPage. cpp.Add the following using statements to MainPage.cpp.

using namespace concurrency;
using namespace std;
using namespace Windows::Storage;
using namespace Windows::Storage::Streams;

Em MainPage. cpp, implemente MainPage::MakeWordList os MainPage::FindCommonWords métodos, e MainPage::ShowResults .In MainPage.cpp, implement the MainPage::MakeWordList, MainPage::FindCommonWords, and MainPage::ShowResults methods. O MainPage::MakeWordList e o MainPage::FindCommonWords executam operações de computação intensiva.The MainPage::MakeWordList and MainPage::FindCommonWords perform computationally-intensive operations. O MainPage::ShowResults método exibe o resultado da computação na interface do usuário.The MainPage::ShowResults method displays the result of the computation in the UI.

// Splits the provided text string into individual words.
task<vector<wstring>> MainPage::MakeWordList(String^ text)
{
    return create_task([text]() -> vector<wstring>
    {
        vector<wstring> words;

        // Add continuous sequences of alphanumeric characters to the string vector.
        wstring current_word;
        for (wchar_t ch : text)
        {
            if (!iswalnum(ch))
            {
                if (current_word.length() > 0)
                {
                    words.push_back(current_word);
                    current_word.clear();
                }
            }
            else
            {
                current_word += ch;
            }
        }

        return words;
    });
}

// Finds the most common words that are at least the provided minimum length.
task<vector<pair<wstring, size_t>>> MainPage::FindCommonWords(const vector<wstring>& words, size_t min_length, size_t count)
{
    return create_task([words, min_length, count]() -> vector<pair<wstring, size_t>>
    {
        typedef pair<wstring, size_t> pair;

        // Counts the occurrences of each word.
        concurrent_unordered_map<wstring, size_t> counts;

        parallel_for_each(begin(words), end(words), [&counts, min_length](const wstring& word)
        {
            // Increment the count of words that are at least the minimum length. 
            if (word.length() >= min_length)
            {
                // Increment the count.
                InterlockedIncrement(&counts[word]);
            }
        });

        // Copy the contents of the map to a vector and sort the vector by the number of occurrences of each word.
        vector<pair> wordvector;
        copy(begin(counts), end(counts), back_inserter(wordvector));

        sort(begin(wordvector), end(wordvector), [](const pair& x, const pair& y)
        {
            return x.second > y.second;
        });

        size_t size = min(wordvector.size(), count);
        wordvector.erase(begin(wordvector) + size, end(wordvector));

        return wordvector;
    });
}

// Shows the most common words on the UI. 
void MainPage::ShowResults(const vector<pair<wstring, size_t>>& commonWords)
{
    wstringstream ss;
    ss << "The most common words that have five or more letters are:";
    for (auto commonWord : commonWords)
    {
        ss << endl << commonWord.first << L" (" << commonWord.second << L')';
    }

    // Update the UI.
    Results->Text = ref new String(ss.str().c_str());
}

Modifique o MainPage construtor para criar uma cadeia de tarefas de continuação que é exibida na interface do usuário as palavras comuns no livro The iLiad by Homer.Modify the MainPage constructor to create a chain of continuation tasks that displays in the UI the common words in the book The Iliad by Homer. As duas primeiras tarefas de continuação, que dividem o texto em palavras individuais e localizam palavras comuns, podem ser demoradas e, portanto, definidas explicitamente para serem executadas em segundo plano.The first two continuation tasks, which split the text into individual words and find common words, can be time consuming and are therefore explicitly set to run in the background. A tarefa de continuação final, que atualiza a interface do usuário, não especifica nenhum contexto de continuação e, portanto, segue as regras de threading de apartamento.The final continuation task, which updates the UI, specifies no continuation context, and therefore follows the apartment threading rules.

MainPage::MainPage()
{
    InitializeComponent();

    // To run this example, save the contents of http://www.gutenberg.org/files/6130/6130-0.txt to your Documents folder.
    // Name the file "The Iliad.txt" and save it under UTF-8 encoding.

    // Enable the progress ring.
    Progress->IsActive = true;

    // Find the most common words in the book "The Iliad".

    // Get the file.
    create_task(KnownFolders::DocumentsLibrary->GetFileAsync("The Iliad.txt")).then([](StorageFile^ file)
    {
        // Read the file text.
        return FileIO::ReadTextAsync(file, UnicodeEncoding::Utf8);

        // By default, all continuations from a Windows Runtime async operation run on the 
        // thread that calls task.then. Specify use_arbitrary to run this continuation 
        // on a background thread.
    }, task_continuation_context::use_arbitrary()).then([this](String^ file)
    {
        // Create a word list from the text.
        return MakeWordList(file);

        // By default, all continuations from a Windows Runtime async operation run on the 
        // thread that calls task.then. Specify use_arbitrary to run this continuation 
        // on a background thread.
    }, task_continuation_context::use_arbitrary()).then([this](vector<wstring> words)
    {
        // Find the most common words.
        return FindCommonWords(words, 5, 9);

        // By default, all continuations from a Windows Runtime async operation run on the 
        // thread that calls task.then. Specify use_arbitrary to run this continuation 
        // on a background thread.
    }, task_continuation_context::use_arbitrary()).then([this](vector<pair<wstring, size_t>> commonWords)
    {
        // Stop the progress ring.
        Progress->IsActive = false;

        // Show the results.
        ShowResults(commonWords);

        // We don't specify a continuation context here because we want the continuation 
        // to run on the STA thread.
    });
}

Observação

Este exemplo demonstra como especificar contextos de execução e como compor uma cadeia de continuaçãos.This example demonstrates how to specify execution contexts and how to compose a chain of continuations. Lembre-se de que, por padrão, uma tarefa que é criada a partir de uma operação assíncrona executa suas continuaçãos no apartamento que chamou task::then .Recall that by default a task that's created from an asynchronous operation runs its continuations on the apartment that called task::then. Portanto, este exemplo usa task_continuation_context::use_arbitrary para especificar que as operações que não envolvem a interface do usuário sejam executadas em um thread em segundo plano.Therefore, this example uses task_continuation_context::use_arbitrary to specify that operations that do not involve the UI be performed on a background thread.

A ilustração a seguir mostra os resultados do CommonWords aplicativo.The following illustration shows the results of the CommonWords app.

Windows Runtime aplicativo CommonWordsWindows Runtime CommonWords app

Neste exemplo, é possível dar suporte ao cancelamento porque os task objetos que dão suporte ao create_async usam um token de cancelamento implícito.In this example, it's possible to support cancellation because the task objects that support create_async use an implicit cancellation token. Defina sua função de trabalho para obter um cancellation_token objeto se suas tarefas precisarem responder ao cancelamento de maneira cooperativa.Define your work function to take a cancellation_token object if your tasks need to respond to cancellation in a cooperative manner. Para obter mais informações sobre o cancelamento na PPL, consulte cancelamento na pplFor more info about cancellation in the PPL, see Cancellation in the PPL

Confira tambémSee also

Runtime de SimultaneidadeConcurrency Runtime