Compartilhar via


Criando operações assíncronas n C++ para aplicativos da Windows Store

Este documento descreve alguns dos principais pontos para ter em mente ao usar o tempo de execução de simultaneidade para gerar operações assíncronas em uma Windows Store aplicativo.

O uso de programação assíncrona é um componente fundamental de Windows Store aplicativo modelo porque ela permite que aplicativos continuem respondendo à entrada do usuário. Você pode iniciar uma tarefa demorada sem bloquear o thread da interface do usuário, e você pode receber os resultados da tarefa mais tarde. Você também pode cancelar tarefas e receber notificações de progresso como tarefas executadas em segundo plano. 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 Windows Store aplicativos. Esse documento ensina como consumir e criar cadeias de assíncrono Tempo de Execução do Windows operações. Esta seção descreve como usar o tempo de execução de simultaneidade para gerar operações assíncronas que podem ser consumidas por outro Tempo de Execução do Windows componente e como controlar o trabalho assíncrono como é executado. Considere a leitura padrões de programação assíncrona e dicas do Hilo (aplicativos da Windows Store usando C++ e XAML) para saber como usamos o tempo de execução de simultaneidade para implementar operações assíncronas em Hilo, um Windows Store aplicativo usando C++ e XAML.

Dica

Você pode usar o biblioteca de padrões paralelos (PPL) e Biblioteca de Agentes Assíncronos em um Windows Store aplicativo.No entanto, você não pode usar o Agendador de tarefas ou o Gerenciador de recursos.Este documento descreve os recursos adicionais que fornece o tempo de execução de simultaneidade que estão disponíveis somente para um Windows Store aplicativo e não a um aplicativo de desktop.

Pontos-chave

  • Use Concurrency:: create_async criar operações assíncronas que podem ser usadas por outros componentes (que podem ser escritos em idiomas diferentes do C++).

  • Use Concurrency:: progress_reporter para notificações de progresso de relatório para componentes que chamar operações assíncronas.

  • Use tokens de cancelamento para habilitar operações assíncronas internas Cancelar.

  • O comportamento do create_async função depende do tipo de retorno da função de trabalho que é passado para ele. Uma função de trabalho que retorna uma tarefa (ou task<T> ou task<void>) é executada sincronizadamente no contexto de chamada create_async. Uma função de trabalho que retorna T ou void é executado em um contexto arbitrário.

  • Você pode usar o concurrency::task::then método para criar uma cadeia de tarefas que são executadas uma após a outra. Em um Windows Store aplicativo, o contexto padrão para as continuações da tarefa depende de como essa tarefa foi construída. Se a tarefa foi criada, passando uma ação assíncrona para o construtor task ou passando uma expressão lambda que retorna uma ação assíncrona, o contexto padrão para todas as continuações dessa tarefa é o contexto atual. Se a tarefa não é construída em uma ação assíncrona, um contexto arbitrário é usado por padrão para a continuação da tarefa. Você pode substituir o contexto padrão com o concurrency::task_continuation_context classe.

Neste documento

  • Criando Operações Assíncronas

  • Exemplo: Criando um componente de tempo de execução C++ do Windows

  • Controlando o Thread de Execução

  • Exemplo: Controlando a execução em um aplicativo da Windows Store com C++ e XAML

Criando Operações Assíncronas

Você pode usar o modelo de tarefa e continuação na paralela padrões PPL (biblioteca) para definir as tarefas em segundo plano, bem como tarefas adicionais que são executados quando a tarefa anterior é concluída. Essa funcionalidade é fornecida pelo Concurrency:: Task classe. Para obter mais informações sobre esse modelo e o task de classe, consulte Paralelismo de tarefa (tempo de execução de simultaneidade).

O Tempo de Execução do Windows é uma interface de programação que você pode usar para criar Windows Store aplicativos que são executados somente em um ambiente especial do sistema operacional. Esses aplicativos usam funções autorizadas, tipos de dados e dispositivos e serem distribuídos a partir de Windows Store. O Tempo de Execução do Windows é representado pelo Interface binária do aplicativo (ABI). A ABI é um contrato binário subjacente que torna Tempo de Execução do Windows APIs disponíveis para linguagens de programação como Visual C++.

Usando o Tempo de Execução do Windows, você pode usar os melhores recursos de várias linguagens de programação e combiná-los em um aplicativo. Por exemplo, você pode criar sua interface do usuário em JavaScript e executar a lógica de aplicativo de computação intensa em um componente C++. A capacidade de executar essas operações de computação intensa em segundo plano é um fator essencial manter a interface do usuário responsivo. Porque o task classe é específico a C++, você deve usar um Tempo de Execução do Windows interface para se comunicar operações assíncronas para outros componentes (que podem ser escritos em idiomas diferentes do C++). O Tempo de Execução do Windows fornece quatro interfaces que você pode usar para representar operações assíncronas:

A noção de um ação significa que a tarefa assíncrona não produz um valor (pense em uma função que retorna void). A noção de um operação significa que a tarefa assíncrona produzir um valor. A noção de progresso significa que a tarefa pode relatar mensagens de andamento ao chamador. JavaScript, o .NET Framework e Visual C++ fornece sua própria maneira de criar instâncias dessas interfaces para uso pelo limite da ABI. Para Visual C++, o tempo de execução de simultaneidade fornece o Concurrency:: create_async função. Esta função cria um Tempo de Execução do Windows operação que representa a conclusão de uma tarefa ou ação assíncrona. O create_async função usa uma função de trabalho (normalmente uma expressão lambda), cria internamente uma task objeto e encapsula a tarefa em um dos quatro assíncrona Tempo de Execução do Windows interfaces.

Dica

Use create_async somente quando você precisa criar a funcionalidade que pode ser acessada de outro idioma ou outro Tempo de Execução do Windows componente.Use o task classe diretamente quando você souber que a operação foi produzida e consumida por código C++ no mesmo componente.

O tipo de retorno de create_async é determinado pelo tipo de seus argumentos. Por exemplo, se sua função de trabalho não retorna um valor e não informa o progresso, create_async retorna IAsyncAction. Se sua função de trabalho não retorna um valor e também relata o progresso, create_async retorna IAsyncActionWithProgress. Para relatar o andamento, forneça um Concurrency:: progress_reporter objeto como o parâmetro para a função de trabalho. A capacidade de relatar o andamento permite que você relate que quantidade de trabalho foi executada e que valor ainda permanece (por exemplo, como uma porcentagem). Ele também permite relatar os resultados assim que estiverem disponíveis.

O IAsyncAction, IAsyncActionWithProgress<TProgress>, IAsyncOperation<TResult>, e IAsyncActionOperationWithProgress<TProgress, TProgress> fornecem interfaces cada um Cancel método que permite que você cancele a operação assíncrona. O task classe funciona com tokens de cancelamento. Quando você usa um token de cancelamento para cancelar o trabalho, o tempo de execução não inicia um novo trabalho assina esse token. Trabalho que já está ativo pode monitorar seu token de cancelamento e interromper quando possível. Esse mecanismo é descrito com mais detalhes no documento Cancelamento no PPL. Você pode conectar o cancelamento da tarefa com o Tempo de Execução do Windows Cancel métodos de duas maneiras. Primeiro, você pode definir a função de trabalho que você passa para create_async tirar uma Concurrency:: cancellation_token objeto. Quando o Cancel método é chamado, esse token de cancelamento é cancelado e as regras de cancelamento normais se aplicam à subsequente task objeto compatível com o create_async chamar. Se você não fornecer um cancellation_token objeto subjacente task objeto define implicitamente. Definir um cancellation_token do objeto quando você precisa responder de forma cooperativa ao cancelamento na sua função de trabalho. A seção exemplo: controlando a execução em um aplicativo da Windows Store com C++ e XAML mostra um exemplo de como executar o cancelamento em um Windows Store aplicativo com c# e XAML que usa um personalizado Tempo de Execução do Windows componente C++.

Aviso

Em uma cadeia de continuações de tarefa, sempre Limpar estado e, em seguida, chame concurrency::cancel_current_task quando concurrency::is_task_cancellation_requested retorna true.Se você retornar antecipadamente em vez de chamar cancel_current_task, as transições de operação para o estado concluído em vez de estado cancelado.

A tabela a seguir resume as combinações que você pode usar para definir as operações assíncronas em seu aplicativo.

Para criar esse Tempo de Execução do Windows interface

Retornar esse tipo de create_async

Transmitir esses tipos de parâmetro para a função de trabalho use um token de cancelamento implícita

Transmitir esses tipos de parâmetro para a função de trabalho use um token de cancelamento explícita

IAsyncAction

void ou task<void>

(nenhum)

(cancellation_token)

IAsyncActionWithProgress<TProgress>

void ou task<void>

(progress_reporter)

(progress_reporter, cancellation_token)

IAsyncOperation<TResult>

T ou task<T>

(nenhum)

(cancellation_token)

IAsyncActionOperationWithProgress<TProgress, TProgress>

T ou task<T>

(progress_reporter)

(progress_reporter, cancellation_token)

Você pode retornar um valor ou uma task objeto da função de trabalho que você passa para o create_async função. Essas variações produzem comportamentos diferentes. Ao retornar um valor, a função de trabalho é encapsulada em um task para que ele pode ser executado em um thread em segundo plano. Além disso, subjacente task usa um token de cancelamento implícita. Por outro lado, se você retornar um task do objeto, a função de trabalho é executado de forma síncrona. Portanto, se você retornar um task do objeto, certifique-se de que também executem quaisquer operações demoradas em sua função de trabalho como tarefas para habilitar seu aplicativo permaneça responsivo. Além disso, subjacente task não usa um token de cancelamento implícita. Portanto, você precisa definir sua função de trabalho tenham um cancellation_token objeto se você precisar de suporte para cancelamento ao retornar um task do objeto de create_async.

O exemplo a seguir mostra várias maneiras de criar um IAsyncAction que pode ser consumido por outro objeto Tempo de Execução do Windows componente.

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

[Superior]

Exemplo: Criando um Componente do Tempo de Execução do Windows C++ e Consumindo-o em C#

Considere um aplicativo que usa XAML e c# para definir a interface do usuário e C++ Tempo de Execução do Windows componente para executar operações de computação intensiva. Neste exemplo, o componente C++ calcula os números em um determinado intervalo são primordiais. Para ilustrar as diferenças entre as quatro Tempo de Execução do Windows interfaces de tarefa assíncrona, iniciar, no Visual Studio, criando uma Blank Solution e nomeá-lo números primos. Em seguida, adicionar à solução um o componente de tempo de execução do Windows do projeto e nomeá-lo PrimesLibrary. Adicione o seguinte código ao arquivo de cabeçalho C++ gerado (Este exemplo renomeia Class1. h para Primes.h). Cada public método define uma das quatro interfaces assíncronas. Os métodos que retornam um valor de retorno um Windows::Foundation::Collections::IVector < int > objeto. Os métodos que informam o andamento produzem double valores que definem a porcentagem de trabalho geral que foi concluída.

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

Dica

Por convenção, nomes de método assíncrono no Tempo de Execução do Windows geralmente terminam com "Async".

Adicione o seguinte código ao arquivo de origem C++ gerado (Este exemplo renomeia Class1. cpp para Primes.cpp). O is_prime função determina se a entrada é primo. Implementam os métodos restantes de Primes classe. Cada chamada para create_async usa uma assinatura que é compatível com o método do qual ele é chamado. Por exemplo, porque Primes::ComputePrimesAsync retorna IAsyncAction, a função de trabalho que é fornecida para create_async não retorna um valor e não requer uma progress_reporter objeto como seu parâmetro.

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

Cada método primeiro executa validação para garantir que os parâmetros de entrada são não negativo. Se um valor de entrada for negativo, o método gerará Platform:: invalidargumentexception. Tratamento de erros é explicado posteriormente nesta seção.

Para consumir esses métodos de um Windows Store aplicativo, usar o Visual c# aplicativo em branco (XAML) modelo para adicionar um segundo projeto à solução do Visual Studio. Este exemplo denomina o projeto números primos. Depois do números primos do projeto, adicione uma referência para o PrimesLibrary projeto.

Adicione o seguinte código para MainPage. XAML. Esse código define a interface do usuário para que você possa chamar o componente C++ e exibir resultados.

<Page
    x:Class="Primes.MainPage"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Primes"
    xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="https://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 seguinte código para o MainPage classe MainPage. XAML. Esse código define uma Primes objeto e os manipuladores de eventos do botão.

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 o async e await palavras-chave para atualizar a interface do usuário depois que as operações assíncronas são concluídas. Para obter informações sobre os padrões assíncronos que estão disponíveis para c# e Visual Basic, consulte padrões assíncronos em aplicativos da Windows Store com c# e padrões assíncronos em aplicativos da Windows Store com VB.

O getPrimesCancellation e cancelGetPrimes métodos trabalham juntos para permitir que o usuário cancelar a operação. Quando o usuário escolhe o Cancelar botão, o cancelGetPrimes chamadas de método IAsyncOperationWithProgress < TResult, TProgress >:: Cancel para cancelar a operação. 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 Tempo de Execução do Windows para comunicar-se de que o cancelamento foi concluída. Para obter mais informações sobre o modelo de cancelamento, consulte Cancelamento no PPL.

Importante

Para habilitar o tempo de execução de simultaneidade relatar corretamente para o Tempo de Execução do Windows que ele cancelou a operação, não detectar esse tipo de exceção interna.Isso significa que você deve também não capturar todas as exceções (catch (...)).Se você deve capturar todas as exceções, relançar a exceção para garantir que o Tempo de Execução do Windows possa concluir a operação de cancelamento.

A ilustração a seguir mostra o números primos aplicativo depois de cada opção foi escolhida.

Aplicativo da Windows Store números primos

Para obter exemplos que usam create_async para criar tarefas assíncronas que podem ser consumidas por outros idiomas, consulte usando C++ no exemplo Bing Maps Trip Optimizer e operações assíncronas do Windows 8 em C++ com PPL.

[Superior]

Controlando o Thread de Execução

O Tempo de Execução do Windows usa o modelo de threading de COM. Nesse modelo, os objetos são hospedados em apartments diferentes, dependendo de como eles lidam com suas sincronizações. Objetos de thread-safe são hospedados no multi-threaded apartment (MTA). Objetos que devem ser acessados por um único thread são hospedados em um single-threaded apartment (STA).

Em um aplicativo que tenha uma interface do usuário, o thread ASTA (aplicativo STA) é responsável por bombeando mensagens de janela e é o único thread no processo que pode atualizar os controles hospedados STA da interface do usuário. Isso tem duas conseqüências. Primeiro, para permitir que o aplicativo permaneça responsivo, todas as operações de e/s e uso intensivo de CPU devem não ser executadas no thread ASTA. Em segundo lugar, os resultados que vêm de threads de segundo plano devem ser empacotados para ASTA para atualizar a interface do usuário. No C++ Windows Store aplicativo, MainPage e todas as outras páginas de XAML executam o ATSA. Portanto, o continuações de tarefa são declaradas no ASTA são executadas lá por padrão, para que você possa atualizar controles diretamente no corpo da continuação. No entanto, se você aninhar uma tarefa em outra tarefa, todas as continuações nessa tarefa aninhada executar no MTA. Portanto, você precisa considerar se deve especificar explicitamente em qual contexto esses continuações executado.

Uma tarefa que é criada a partir de uma operação assíncrona, como IAsyncOperation<TResult>, usa semânticas especiais que podem ajudar a ignoram os detalhes de threads. Embora uma operação pode ser executado em um thread em segundo plano (ou ele não pode ser feito por um thread em todos os), seus continuações são por padrão garantida para executar no apartment que iniciou as operações de continuação (em outras palavras, de apartment chamado task::then). Você pode usar o concurrency::task_continuation_context classe para controlar o contexto de execução de uma continuação. Use esses métodos auxiliares estáticos para criar task_continuation_context objetos:

Você pode passar um task_continuation_context do objeto para o Task:: Then método controlar explicitamente o contexto de execução da continuação ou você pode passar a tarefa para outra apartment e, em seguida, chamar o task::then método para controlar implicitamente o contexto de execução.

Importante

Porque o thread da interface do usuário principal de Windows Store aplicativos executados em STA, continuações que você cria em que STA por padrão é executado no STA.Da mesma forma, continuações criada no MTA executados em MTA.

A seção a seguir mostra um aplicativo que lê um arquivo no disco, localiza as palavras mais comuns desse arquivo e, em seguida, mostra os resultados na interface do usuário. A operação final, atualizando a interface do usuário ocorre no thread da interface do usuário.

Importante

Esse comportamento é específico para Windows Store aplicativos.Para aplicativos de desktop, você não controlar onde continuações executam.Em vez disso, o agendador escolherá um thread de trabalho para executar cada continuação.

Importante

Não chame concurrency::task::wait no corpo de uma continuação que é executado no STA.Caso contrário, o tempo de execução gera concurrency::invalid_operation porque esse método bloqueia o segmento atual e pode fazer com que o aplicativo pare de responder.No entanto, você pode chamar o método concurrency::task::get para receber o resultado da tarefa antecedente em uma continuação baseada em tarefa.

[Superior]

Exemplo: Controlando a Execução em um Aplicativo do Windows Store com C++ e XAML

Considere um aplicativo XAML de C++ que lê um arquivo no disco, localiza as palavras mais comuns desse arquivo e, em seguida, mostra os resultados na interface do usuário. Para criar esse aplicativo, iniciar, no Visual Studio, criando uma Windows Store aplicativo em branco (XAML) do projeto e nomeá-lo CommonWords. Em seu manifesto de aplicativo, especifique o biblioteca de documentos capacidade de permitir que o aplicativo acessar a pasta de documentos. Também adicione o tipo de arquivo de texto (. txt) à seção declarations do manifesto do aplicativo. Para obter mais informações sobre os recursos do aplicativo e declarações, consulte pacotes de aplicativos e implantação.

Atualização de Grid elemento em MainPage. XAML para incluir um ProgressRing elemento e um TextBlock elemento. A ProgressRing indica que a operação está em andamento e o TextBlock mostra os resultados do cálculo.

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

Adicione o seguinte #include instruções para pch.

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

Adicione as seguintes declarações de método para o MainPage classe (MainPage).

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 o seguinte using instruções de MainPage.cpp.

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

No MainPage.cpp, implemente o MainPage::MakeWordList, MainPage::FindCommonWords, e MainPage::ShowResults métodos. O MainPage::MakeWordList e MainPage::FindCommonWords executar operações de computação intensa. O MainPage::ShowResults método exibe o resultado do cálculo na interface do usuário.

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

Modificar o MainPage construtor para criar uma cadeia de tarefas de continuação que exibe na interface do usuário, as palavras comuns no catálogo de a Ilíada por Homer. As tarefas de dois continuação primeira, dividir o texto em palavras individuais e localizar palavras comuns, podem ser demoradas e, portanto, são definidas explicitamente para ser executado em segundo plano. A tarefa final de continuação, que atualiza a interface do usuário, não especifica nenhum contexto de continuação e, portanto, segue o regras de segmentação de compartimento.

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

Dica

Este exemplo demonstra como especificar os contextos de execução e como compor uma cadeia de continuações.Lembre-se de que por padrão uma tarefa que é criada a partir de uma operação assíncrona é executado seus continuações apartment chamado task::then.Portanto, este exemplo usa task_continuation_context::use_arbitrary para especificar que as operações que envolvem a interface do usuário seja executada em um thread em segundo plano.

A ilustração a seguir mostra os resultados de CommonWords aplicativo.

Aplicativo da Windows Store CommonWords

Neste exemplo, é possível oferecer suporte ao cancelamento porque o task objetos com suporte create_async usar um token de cancelamento implícita. Definir sua função de trabalho tenham um cancellation_token se suas tarefas precisam responder ao cancelamento de forma cooperativa do objeto. Para obter mais informações sobre cancelamento no PPL, consulte Cancelamento no PPL

[Superior]

Consulte também

Conceitos

Tempo de Execução de Simultaneidade