Criando operações assíncronas n C++ para aplicativos da Windows Store
Este documento descreve alguns de chave para ter em mente quando você usa o tempo de execução de simultaneidade para gerar operações assíncronas em um aplicativo de Windows Store .
O uso de programação assíncrona é um componente-chave no modelo de aplicativo de Windows Store porque ela permite que aplicativos para continuar responsivo a entrada do usuário.Você pode iniciar uma tarefa de execução demorada não bloquear o encadeamento de interface do usuário, e você pode receber os resultados da tarefa posteriormente.Você também pode cancelar tarefas e receber notificações de progresso como tarefas executadas no plano de fundo.O documento Em C++ programação assíncrona fornece uma visão geral do padrão assíncrono que está disponível no Visual C++ para criar aplicativos de Windows Store .Esse documento ensina como consumir e criar cadeias de operações assíncronas de Tempo de Execução do Windows .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 componente de Tempo de Execução do Windows e como controlar como o trabalho assíncrono é executado.Considere também ler Padrões e dicas de programação de Async em 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 aplicativo de Windows Store usando C++ e XAML.
Observação |
---|
Você pode usar Biblioteca de padrões paralelos (PPL) e Biblioteca de agentes assíncrono em um aplicativo Windows Store.No entanto, você não pode usar o agendador de tarefa ou o Gerenciador de Recursos.Este documento descreve os recursos adicionais que o tempo de execução de simultaneidade fornece que está disponível somente para um aplicativo de Windows Store , e não em um aplicativo da área de trabalho. |
Chave
Use concurrency::create_async para criar operações assíncronas que podem ser usados por outros componentes (que podem ser escritos em linguagens diferentes de C++).
Use concurrency::progress_reporter para relatar notificações de progresso a componentes que chamam as operações assíncronas.
Use tokens cancelar para ativar operações assíncronas internas para cancelar.
O comportamento da função de create_async depende do tipo de retorno da função de trabalho que você for passada.Uma função de trabalho que retorna executa uma tarefa de task<T> (ou) **task<void>**de forma síncrona no contexto que chamou create_async.Uma função de trabalho que retorna T ou void executa em um contexto arbitrário.
Você pode usar o método de concurrency::task::then para criar uma cadeia das tarefas que executam um após o outro.Em um aplicativo de Windows Store , o contexto padrão para as continuações de uma tarefa depende de como a tarefa foi construída.Se a tarefa foi criada passando uma ação assíncrona para o construtor de tarefas, ou passando um expressão lambda que retorna uma ação assíncrona, então o contexto padrão para todas as continuações da tarefa é o contexto atual.Se a tarefa não é construída de uma ação assíncrona, então um contexto arbitrário é usado por padrão para as continuações de tarefas.Você pode substituir o contexto padrão com a classe de concurrency::task_continuation_context .
Neste documento
Criando operações assíncronas
Exemplo: Criando o componente de c++ Tempo de Execução 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 a tarefa e o modelo de continuação de linha na biblioteca (PPL) dos padrões de paralela definir tarefas em segundo plano e as tarefas adicionais que executam quando a tarefa termina anterior.Esta funcionalidade é fornecida pela classe de concurrency::task .Para obter mais informações sobre este modelo e da classe de task , consulte Paralelismo de tarefa (tempo de execução de simultaneidade).
Tempo de Execução do Windows é uma interface de programação que você pode usar para criar aplicativos de Windows Store que executam somente em um ambiente especial do sistema operacional.Tal uso de aplicativos autorizado funciona, tipos de dados, e dispositivos, e é distribuído de Windows Store.Tempo de Execução do Windows é representado pela interface de binária de aplicativo (ABI).ABI é um contrato binário subjacente que faz APIs de Tempo de Execução do Windows disponíveis para as linguagens de programação como Visual C++.
Usando Tempo de Execução do Windows, você pode usar os melhores recursos de várias linguagens de programação e combiná-las em um aplicativo.Por exemplo, você pode criar a interface do usuário em Javascript e execute a lógica computacional- intensa de aplicativo no componente de c++.A capacidade de executar essas operações computacional- como no plano de fundo é um fator chave em manter sua interface do usuário responsivo.Porque a classe de task são específicas para C++, você deve usar uma interface de Tempo de Execução do Windows para comunicar operações assíncronas a outros componentes (que podem ser escritos em linguagens diferentes de C++).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íncrono.Windows::Foundation::IAsyncActionWithProgress<TProgress>
Representa uma ação assíncrono que relata o andamento.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 ande.
A noção de uma 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 uma operação significa que a tarefa assíncrono gera um valor.A noção de progresso significa que a tarefa pode relatar mensagem de progresso para o chamador.O Javascript, o .NET Framework e Visual C++, cada um fornecem sua própria maneira de criar instâncias dessas interfaces para uso pelo limite de ABI.Para Visual C++, o tempo de execução de simultaneidade fornece a função de concurrency::create_async .Esta função cria uma ação ou uma operação assíncrona de Tempo de Execução do Windows que representa a conclusão de uma tarefa.A função de create_async usa uma função de trabalho (normalmente uma expressão lambda), internamente cria um objeto de task , e as envolve que tarefa em uma das quatro interfaces assíncronas de Tempo de Execução do Windows .
Observação |
---|
Use create_async somente quando você tem que criar a funcionalidade que pode ser acessada de outra linguagem ou outro componente de Tempo de Execução do Windows .Use a classe de task diretamente quando você souber que a operação é gerada e consumida pelo 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 relata o andamento, create_async retorna IAsyncAction.Se sua função de trabalho não retorna um valor e também relatórios progride, create_async retorna IAsyncActionWithProgress.Para relatar o andamento, fornecer um objeto de concurrency::progress_reporter como o parâmetro para sua função de trabalho.A capacidade do reporting o progresso permitem reportar que quantidade de trabalho foi executada e quantidade que ainda permanece (por exemplo, como uma porcentagem).Também permite relatar resultados como se tornam disponíveis.
IAsyncAction, IAsyncActionWithProgress<TProgress>, IAsyncOperation<TResult>, e interfaces cada um de IAsyncActionOperationWithProgress<TProgress, TProgress> fornecem um método de Cancel que permite que você para cancelar a operação assíncrona.Os trabalhos da classe de task com tokens cancelar.Quando você usa um token cancelar para cancelar o trabalho, o tempo de execução não começa a trabalho que a assinatura esse token.Trabalhar que já está ativa pode monitorar o símbolo de cancelar o e parar quando possa.Esse mecanismo é descrito em detalhes no documento Cancelar o PPL.Você pode conectar cancelamento de tarefa com os métodos de Tempo de Execução do WindowsCancel de duas maneiras.Primeiro, você pode definir a função de trabalho que você passa a create_async para levar um objeto de concurrency::cancellation_token .Quando o método de Cancel é chamado, este token cancelar é cancelado e as regras normais cancelar aplicam a task o objeto subjacente que oferece suporte a chamada de create_async .Se você não fornecer um objeto de cancellation_token , o objeto subjacente de task define um implicitamente.Defina um objeto de cancellation_token quando você precisa responder cooperativa para cancelar na 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 cancelamento em um aplicativo de Windows Store com C# e XAML que usa um componente personalizado de Tempo de Execução do Windows C++.
Cuidado |
---|
Em uma cadeia de continuações de tarefas, limpe sempre o estado e então chame concurrency::cancel_current_task quando concurrency::is_task_cancellation_requested retorna true.Se você retorna no início em vez de chamada cancel_current_task, a operação faz a transição de estado concluído em vez de estado cancelado. |
A tabela a seguir resume as combinações que você pode usar para definir operações assíncronas em seu aplicativo.
Para criar esta interface de Tempo de Execução do Windows |
Retornar esse tipo de create_async |
Passar esses tipos de parâmetro na função de trabalho para usar um token implícito cancelar |
Passar esses tipos de parâmetro na função de trabalho para usar um token explícito cancelar |
---|---|---|---|
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 um objeto de task da função de trabalho que você passa para a função de create_async .Essas variações geram diferentes comportamentos.Quando você retorna um valor, a função de trabalho está envolvida em task para que ele possa ser executada em um segmento de plano de fundo.Além disso, task subjacente usa um token implícito cancelar.Por outro lado, se você retorna um objeto de task , a função executa trabalho de forma síncrona.Como consequência, se você retorna um objeto de task , certifique-se de que todas as operações longas na função de trabalho também executar tarefas como ativar seu aplicativo para continuar responsivas.Além disso, task base não usa um token implícito cancelar.Como consequência, você precisa definir sua função de trabalho para obter um objeto de cancellation_token se você precisar de suporte para o botão quando você retorna um objeto de task de create_async.
O exemplo a seguir mostra várias maneiras de criar um objeto de IAsyncAction que pode ser consumido por outro componente de Tempo de Execução do Windows .
// 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 o componente e consumi-lo de c++ Tempo de Execução do Windows C#
Considere um aplicativo que usa C# e XAML para definir a interface do usuário e o componente de c++ Tempo de Execução do Windows para executar operações cálculo- como.Nesse exemplo, os cálculos do componente C++ que numera em um determinado intervalo são chave.Para ilustrar as diferenças entre as quatro interfaces assíncronas de tarefa de Tempo de Execução do Windows , inicie, no Visual Studio, criando Solução em branco e nomeando o Apronta.Adicionar à solução um projeto de Componente de Tempo de Execução do Windows e a nomeação dele PrimesLibrary.Adicione o seguinte código ao arquivo de cabeçalho gerado C++ (este exemplo renomeia Class1.h a Primes.h).Cada método de public define uma das quatro interfaces assíncronas.Os métodos que retornam um Windows::Foundation::Collections::IVector<int> valor de retorno um objeto.Os métodos que reportam os valores de double de produto de progresso 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);
};
}
Observação |
---|
Por convenção, os nomes de método assíncrono em Tempo de Execução do Windows normalmente terminam com “Async”. |
Adicione o seguinte código ao arquivo de origem gerado C++ (este exemplo renomeia Class1.cpp a Primes.cpp).A função de is_prime determina se a entrada é principal.Os métodos restantes implementam a classe de Primes .Cada chamada a create_async usa uma assinatura compatível com o método que é 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 recebe um objeto de progress_reporter 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 executa primeiro validação para garantir que os parâmetros de entrada são não negativos.Se um valor de entrada for negativo, o gera Platform::InvalidArgumentExceptiono método.Manipulação de erro é explicado posteriormente nesta seção.
Para consumir esses métodos de um aplicativo de Windows Store , use o modelo Visual C# Aplicativo em branco (XAML) para adicionar um segundo projeto para a solução do Visual Studio.Este exemplo nomeie o projeto Apronta.Em seguida, do projeto de Apronta , adicione uma referência ao projeto de PrimesLibrary .
Adicione o seguinte código a MainPage.xaml.Esse código define interface do usuário para que você possa chamar os resultados do componente e exibir C++.
<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 à classe de MainPage em MainPage.xaml.Esse código define um objeto de Primes e 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 as palavras-chave de async e de await para atualizar a interface do usuário após operações assíncronas concluírem.Para obter informações sobre padrões assíncronas que estão disponíveis para C# e em Visual Basic, consulte Padrão assíncrono em aplicativos da Windows Store com C# e Padrão assíncrono em aplicativos da Windows Store com VB.
Os métodos de getPrimesCancellation e de cancelGetPrimes funcionam juntos para permitir que o usuário cancele a operação.Quando o usuário escolha o botão de Cancelar , chamadas de método IAsyncOperationWithProgress<TResult, TProgress>::CancelcancelGetPrimes para cancelar a operação.O tempo de execução de concorrência, que gerencia a operação assíncrona subjacente, gera um tipo de exceção interna que é capturado por Tempo de Execução do Windows para se comunicar que o botão foi concluída.Para obter mais informações sobre o modelo de cancelamento, consulte Cancelar o PPL.
Importante |
---|
Para ativar o tempo de execução de simultaneidade para relatar corretamente a Tempo de Execução do Windows que cancelou a operação, não capturar esse tipo de exceção interna.Isso significa que você não deve também captura todas as exceçõescatch (...)().Se você deve captura todas as exceções, relançar a exceção para garantir que Tempo de Execução do Windows possa concluir a operação de cancelamento. |
A ilustração a seguir mostra o aplicativo de Apronta após cada opção foi escolhida.
Para exemplos que usam create_async para criar as tarefas assíncronas que podem ser consumidas por outras linguagens, consulte Usando C++ em Bing mapeia o exemplo de otimizador de processamento e Operações assíncronas Windows 8 em C++ com o PPL.
Superior[]
Controlando o thread de execução
Tempo de Execução do Windows usa o modelo de segmentação COM.Nesse modelo, objetos são hospedados em construção diferentes, dependendo de como tratar a sincronização.Os objetos com segurança de segmentos são hospedados em um apartamento multithreaded (MTA).Os objetos que devem ser acessados por um único segmento são hospedados em um compartimento de único thread (STA).
Em um aplicativo que tenha interface do usuário, o segmento de ASTA aplicativo (STA) é responsável por bombear mensagens de janela e é o único segmento no processo que pode atualizar os controles hospedados STA- de interface do usuário.Isso tem duas consequências.Primeiro, para ativar o aplicativo para continuar responsivas, todas as operações de E/S da CPU como e não devem ser executadas no encadeamento de ASTA.Segundo, resulta provenientes de segmentos de plano de fundo deve ser lido de volta para o ASTA para atualizar a interface do usuário.No aplicativo de Windows Store c++, MainPage e o outro XAML página toda a execução em ATSA.Como consequência, as continuações de tarefa que são declaradas em ASTA são executadas lá por padrão para que você possa atualizar controles diretamente no corpo de continuação de linha.No entanto, se você aninha uma tarefa em outra tarefa, todas as continuações tarefa aninhada em que executam em MTA.Como consequência, você precisa considerar se especificar explicitamente em que contexto execução dessas continuações.
Uma tarefa que é criada de uma operação assíncrona, como IAsyncOperation<TResult>, a semântica dos usos especial que podem ajudá-lo a evitar segmentação detalha.Embora uma operação pode executar em um thread em segundo plano (ou ele não pode ser suportado por um segmento de qualquer), sua continuações por padrão são garantidas para executar no apartment que iniciou as operações de continuação de linha (ou seja apartment que task::thenchamado).Você pode usar a classe de concurrency::task_continuation_context para controlar o contexto de execução de uma continuação.Use esses métodos estáticos auxiliar para criar objetos de task_continuation_context :
Use concurrency::task_continuation_context::use_arbitrary para especificar que a seguir é executado em um segmento de plano de fundo.
Use concurrency::task_continuation_context::use_current para especificar que a seguir é executado no thread que chamou task::then.
Você pode passar um objeto de task_continuation_context para o método de task::then para controlar explicitamente o contexto de execução de continuação de linha ou você pode passar a tarefa para outro) e chamar o método de task::then para controlar implicitamente o contexto de execução.
Importante |
---|
Porque o segmento principal de interface de usuário de aplicativos de Windows Store é executado sob STA, as continuações que você cria em que STA por padrão executam no STA.Da mesma forma, as continuações que você cria em execução no MTA MTA. |
A seção a seguir mostra um aplicativo que lê um arquivo de disco, localiza a palavra mais comuns no arquivo, e mostra os resultados da interface do usuário.A operação final, atualizando interface do usuário, ocorre no encadeamento de interface do usuário.
Importante |
---|
Esse comportamento é específico para aplicativos de Windows Store .Para aplicativos desktop, você não controla onde execução de continuações.Em vez disso, o agendador escolhe um segmento de trabalho que para executar cada continuação. |
Importante |
---|
Não chamar concurrency::task::wait no corpo de uma continuação executado em 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 se torne sem resposta.No entanto, você pode chamar o método de concurrency::task::get para receber o resultado da tarefa antecedente em uma continuação chave com base. |
Superior[]
Exemplo: Controlando a execução em um aplicativo de Windows Store com C++ e XAML
Considere a aplicação de c++ XAML que lê um arquivo de disco, localiza a palavra mais comuns no arquivo, e mostra os resultados da interface do usuário.Para criar este aplicativo, inicie, no Visual Studio, criando um projeto de Windows StoreNulo o aplicativo (XAML) e nomeando o CommonWords.No manifesto do aplicativo, especifique o recurso de Biblioteca de Documentos ativar o aplicativo para acessar a pasta documentos.Também adicionar o tipo de arquivo de texto (.txt) à seção de declarações de manifesto do aplicativo.Para obter mais informações sobre recursos e as declarações do aplicativo, consulte Pacotes e implantação do aplicativo.
Atualizando o elemento de Grid em MainPage.xaml para incluir um elemento de ProgressRing e um elemento de TextBlock .ProgressRing indica que a operação está em andamento e mostra os resultados de TextBlock de computação.
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<ProgressRing x:Name="Progress"/>
<TextBlock x:Name="Results" FontSize="16"/>
</Grid>
Adicione as seguintes declarações de #include a pch.h.
#include <sstream>
#include <ppltasks.h>
#include <concurrent_unordered_map.h>
Adicione as declarações de seguinte método à classe de MainPage 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 seguintes declarações de using a MainPage.cpp.
using namespace concurrency;
using namespace std;
using namespace Windows::Storage;
using namespace Windows::Storage::Streams;
Em MainPage.cpp, implemente MainPage::MakeWordList, MainPage::FindCommonWords, os métodos e de MainPage::ShowResults .MainPage::MakeWordList e MainPage::FindCommonWords executam operações computacional- como.O método de MainPage::ShowResults exibe o resultado de computação da 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());
}
Modifique o construtor de MainPage para criar uma cadeia de tarefas de continuação de linha exibida na interface do usuário que um comum exprime no catálogo o Ilíada localização.As duas primeiras tarefas a seguir, que divide o texto em palavras individuais e em palavras comuns de localização, podem ser demoradas e consequentemente são definidas explicitamente para executar no plano de fundo.A tarefa final de continuação de linha, que atualiza interface do usuário, não especificar qualquer contexto de continuação de linha, e como consequência segue regras de Apartment threads.
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ções.Lembre que por padrão uma tarefa que é criada de uma operação assíncrona executa suas continuações no apartment que chamou task::then.Como consequência, este exemplo usa task_continuation_context::use_arbitrary para especificar que as operações que não envolvem interface de usuário são executadas em um segmento de plano de fundo. |
A ilustração a seguir mostra os resultados do aplicativo de CommonWords .
Nesse exemplo, é possível suportar cancelamento porque task objetos que uso de create_async um símbolo de suporte implícito cancelar.Defina a função de trabalho para obter um objeto de cancellation_token se suas tarefas precisa responder ao cancelamento de uma maneira cooperativa.Para obter mais informações sobre o botão no PPL, consulte Cancelar o PPL
Superior[]