Aplicativos do Windows
Recolher sumário
Expandir sumário
Informações
O tópico solicitado está sendo mostrado abaixo. No entanto, este tópico não está incluído nesta biblioteca.
É recomendável usar o Visual Studio 2017

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

 

Publicado: julho de 2016

Este documento descreve alguns dos principais pontos para ter em mente ao usar a classe task para produzir operações assíncronas baseadas em Windows ThreadPool em um Windows Store 8.x aplicativo.

O uso de programação assíncrona é um componente fundamental de Windows Store 8.x modelo de aplicativo porque ele permite que os 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 as 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 8.x 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 os tipos em ppltasks.h para produzir 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 no Hilo (aplicativos da Windows Store usando C++ e XAML) para saber como usamos a classe de tarefa para implementar operações assíncronas no Hilo, um Windows Store 8.x aplicativo usando o C++ e XAML.

System_CAPS_noteObservação

Você pode usar o biblioteca de padrões paralelos (PPL) e Biblioteca de Agentes Assíncronos em um Windows Store 8.x 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 a PPL que estão disponíveis apenas para um Windows Store 8.x aplicativo e não a um aplicativo de desktop.

  • 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 notificações de andamento do relatório para componentes que chamam 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 (em task<T> ou task<void>) é executado de forma síncrona 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 8.x aplicativo, o contexto padrão para a continuação da tarefa depende de como essa tarefa foi criada. 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 de tarefa é o contexto atual. Se a tarefa não é criada com 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.

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 seja 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 8.x aplicativos que são executados somente em um ambiente especial do sistema operacional. Esses aplicativos usam funções autorizadas, tipos de dados e dispositivos, além de serem distribuídos a partir da Windows Store. O Tempo de Execução do Windows é representado pela Interface Binária de Aplicativo (ABI). ABI é um contrato binário subjacente que torna as APIs do Tempo de Execução do Windows disponíveis para as 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 intensiva em um componente do C++. A capacidade de executar essas operações intensiva em segundo plano é um fator essencial para manter a interface do usuário responsiva. Porque o task classe é específica para o 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:

Windows::Foundation::IAsyncAction

Representa uma ação assíncrona.

Windows::Foundation::IAsyncActionWithProgress < TProgress >

Representa uma ação assíncrona que relata o progresso.

Windows::Foundation::IAsyncOperation < TResult >

Representa uma operação assíncrona que retorna um resultado.

Windows::Foundation::IAsyncOperationWithProgress < TResult, TProgress >

Representa uma operação assíncrona que retorna um resultado e relatórios de andamento.

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 progresso para o chamador. JavaScript, o .NET Framework e Visual C++ fornece sua própria maneira de criar instâncias dessas interfaces para uso pelo limite de ABI. Para Visual C++, a PPL fornece o concurrency::create_async função. Esta função cria um Tempo de Execução do Windows ação ou operação que representa a conclusão de uma tarefa 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.

System_CAPS_noteObservação

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 relatar o andamento, 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 progresso, forneça um concurrency::progress_reporter objeto como o parâmetro para a função de trabalho. A capacidade para relatar o progresso 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.

As interfaces IAsyncAction, IAsyncActionWithProgress<TProgress>, IAsyncOperation<TResult> e IAsyncActionOperationWithProgress<TProgress, TProgress> fornecem um método Cancel que permite cancelar 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 mais detalhadamente no documento Cancelamento no PPL. Você pode conectar o cancelamento da tarefa com o Tempo de Execução do WindowsCancel métodos de duas maneiras. Primeiro, é possível definir a função de trabalho que você transmite a create_async para usar um objeto concurrency::cancellation_token. Quando o Cancel método é chamado, esse token de cancelamento será cancelada e as regras normais de cancelamento se aplicam subjacente task objeto que ofereça suporte a create_async chamar. Se você não fornecer um objeto cancellation_token, o objeto task subjacente define um de forma implícita. Defina um objeto cancellation_token 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 8.x aplicativo com c# e XAML que usa um personalizado Tempo de Execução do Windows componente C++.

System_CAPS_warningAviso

Em uma cadeia de continuações de tarefa, sempre Limpar estado e, em seguida, chame concurrency::cancel_current_task quando o token de cancelamento é cancelado. Se você retornar no início, 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

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

Passar esses tipos de parâmetro para a função de trabalho para usar 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 de objeto, certifique-se de que quaisquer operações longas em sua função de trabalho também executar 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 de objeto 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.
    });
});

Considere um aplicativo que usa XAML e c# para definir a interface do usuário e um C++ Tempo de Execução do Windows componente para executar operações com uso intensivo de computação. Neste exemplo, o componente C++ calcula os números em um determinado intervalo são primos. Para ilustrar as diferenças entre os quatro Tempo de Execução do Windows interfaces de tarefa assíncrona, iniciar, no Visual Studio, criando um solução em branco e nomeá-lo Primes. 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 para o 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);
    };
}
System_CAPS_noteObservação

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 para o 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 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 exige 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 8.x aplicativo, use o Visual C# aplicativo em branco (XAML) modelo para adicionar um segundo projeto à solução do Visual Studio. Este exemplo denomina o projeto Primes. Depois do Primes do projeto, adicione uma referência para o PrimesLibrary projeto.

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

<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 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 de concluir as operações assíncronas. 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 funcionam 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 >:: Cancelar 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 detectada pelo Tempo de Execução do Windows para comunicar-se de que o cancelamento foi concluído. Para obter mais informações sobre o modelo de cancelamento, consulte Cancelamento no PPL.

System_CAPS_importantImportante

Para habilitar a PPL relate 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 pode concluir a operação de cancelamento.

A ilustração a seguir mostra o Primes aplicativo depois de cada opção foi escolhida.

O armazenamento do Windows Primes app

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

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 de interface hospedado STA. Isso tem duas consequê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 em segundo plano devem ser empacotados para ASTA para atualizar a interface do usuário. No C++ Windows Store 8.x aplicativo, MainPage e executam todas as outras páginas de XAML a ATSA. Portanto, o continuações de tarefa que 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 executar esses continuações.

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), as continuações são por padrão sempre executado no apartment que iniciou as operações de continuação (em outras palavras, a partir 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 para 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.

System_CAPS_importantImportante

Porque o thread da interface do usuário principal de Windows Store 8.x aplicativos executados em STA, continuações que você cria em que STA por padrão são executados no STA. Da mesma forma, continuações que você cria no MTA execute no 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, a interface do usuário, a atualização ocorre no thread da interface do usuário.

System_CAPS_importantImportante

Esse comportamento é específico para Windows Store 8.x 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.

System_CAPS_importantImportante

Não chame concurrency::task::wait no corpo de uma continuação que é executado no STA. Caso contrário, o tempo de execução lança 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 concurrency::task::get método para receber o resultado da tarefa antecedente em uma continuação baseado em tarefa.

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 8.xaplicativo 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. Adicione também o tipo de arquivo de texto (. txt) à seção declarations do manifesto do aplicativo. Para obter mais informações sobre declarações e os recursos de aplicativo, consulte pacotes de aplicativo e implantação.

Atualizar o Grid elemento em MainPage. XAML para incluir um ProgressRing elemento e um TextBlock elemento. O 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 pch.

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

Adicione as seguintes declarações de método para o MainPage classe (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 o seguinte using instruções 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 intensiva. 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 de palavras comuns no catálogo de a Ilíada por Homer. As tarefas de dois continuação primeiro, qual dividir o texto em palavras individuais e localizar palavras comuns, podem ser demoradas e, portanto, são definidas explicitamente para executar 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.
    });
}
System_CAPS_noteObservação

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 as continuações de 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.

Os Windows armazenam app CommonWords

Neste exemplo, é possível oferecer suporte ao cancelamento porque o task objetos que oferecem suporte a 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

Mostrar:
© 2018 Microsoft