Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu belgede, bir Evrensel Windows Çalışma Zamanı (UWP) uygulamasında Windows ThreadPool tabanlı zaman uyumsuz işlemler üretmek için görev sınıfını kullandığınızda göz önünde bulundurmanız gereken bazı önemli noktalar açıklanmaktadır.
Zaman uyumsuz programlama kullanımı, uygulamaların kullanıcı girişlerine yanıt vermeye devam etmelerini sağladığından Windows Çalışma Zamanı uygulama modelindeki önemli bir bileşendir. Kullanıcı arabirimi iş parçacığını engellemeden uzun süre çalışan bir görev başlatabilir ve görevin sonuçlarını daha sonra alabilirsiniz. Ayrıca, görevler arka planda çalıştırılırken görevleri iptal edebilir ve ilerleme bildirimleri alabilirsiniz. C++ dilindeki zaman uyumsuz programlama belgesi, UWP uygulamaları oluşturmak için Visual C++ uygulamasında kullanılabilen zaman uyumsuz desene genel bir bakış sağlar. Bu belgede asenkron Windows Çalışma Zamanı işlemlerinin zincirlerinin nasıl kullanılacağı ve oluşturulacağı açıklanmaktadır. Bu bölümde, ppltasks.h dosyasındaki türlerin başka bir Windows Çalışma Zamanı bileşeni tarafından kullanılabilecek zaman uyumsuz işlemler üretmek için nasıl kullanılacağı ve zaman uyumsuz çalışmanın nasıl yürütüldüğünün nasıl denetlendiği açıklanmaktadır. Ayrıca C++ ve XAML kullanan bir Windows Çalışma Zamanı uygulaması olan Hilo'da zaman uyumsuz işlemleri uygulamak için görev sınıfını nasıl kullandığımızı öğrenmek için Hilo'daki (C++ ve XAML kullanan Windows Mağazası uygulamaları) zaman uyumsuz programlama desenlerini ve ipuçlarını okumayı da göz önünde bulundurun.
Uyarı
Bir UWP uygulamasında Paralel Desen kitaplığını (PPL) ve Zaman Uyumsuz Aracılar Kitaplığı'nı kullanabilirsiniz. Ancak, Görev Zamanlayıcı'yı veya Resource Manager'ı kullanamazsınız. Bu belgede, PPL'nin sağladığı ve masaüstü uygulamasında değil yalnızca UWP uygulamasında kullanılabilen ek özellikler açıklanmaktadır.
Önemli noktalar
Diğer bileşenler (C++ dışındaki dillerde yazılmış olabilir) tarafından kullanılabilecek asenkron işlemler oluşturmak için eşzamanlılık::create_async kullanın.
zaman uyumsuz işlemlerinizi çağıran bileşenlere ilerleme durumu bildirimlerini bildirmek için concurrency::p rogress_reporter kullanın.
Asenkron iç işlemlerin iptal edilebilmesi için iptal belirteçlerini kullanın.
İşlevin
create_async
davranışı, ona geçirilen iş işlevinin dönüş türüne bağlıdır. Bir görev (task<T>
veyatask<void>
) döndüren bir işlev,create_async
adı verilen bağlamda eşzamanlı olarak çalışır.T
veyavoid
döndüren bir işlev, rastgele bir bağlamda çalışır.Ardışık olarak çalışan bir görev zinciri oluşturmak için eşzamanlılık::task:::then yöntemini kullanabilirsiniz. UWP uygulamasında, görevin devamı için varsayılan bağlam, görevin nasıl oluşturulduğuna bağlıdır. Görev, zaman uyumsuz bir eylem görev oluşturucuya geçirilerek veya zaman uyumsuz bir eylem döndüren bir lambda ifadesi geçirilerek oluşturulduysa, bu görevin tüm devamı için varsayılan bağlam geçerli bağlamdır. Görev zaman uyumsuz bir eylemden yapılandırılmamışsa, görevin devamları için varsayılan olarak rastgele bir bağlam kullanılır. Varsayılan bağlamı eşzamanlılık::task_continuation_context sınıfıyla geçersiz kılabilirsiniz.
Bu belgede
Zaman Uyumsuz İşlemler Oluşturma
Önceki görev tamamlandığında çalıştırılacak ek görevlerin yanı sıra arka plan görevlerini tanımlamak için Paralel Desenler Kitaplığı'ndaki (PPL) görev ve devamlılık modelini kullanabilirsiniz. Bu işlevsellik concurrency::task sınıfı tarafından sağlanır. Bu model ve task
sınıf hakkında daha fazla bilgi için bkz . Görev Paralelliği.
Windows Çalışma Zamanı, yalnızca özel bir işletim sistemi ortamında çalışan UWP uygulamaları oluşturmak için kullanabileceğiniz bir programlama arabirimidir. Bu tür uygulamalar yetkili işlevleri, veri türlerini ve cihazları kullanır ve Microsoft Store'dan dağıtılır. Windows Çalışma Zamanı, Uygulama İkili Arabirimi (ABI) tarafından temsil edilir. ABI, Windows Çalışma Zamanı API'lerini Visual C++ gibi programlama dillerinde kullanılabilir hale getiren temel bir ikili anlaşmadır.
Windows Çalışma Zamanı'nı kullanarak çeşitli programlama dillerinin en iyi özelliklerini kullanabilir ve bunları tek bir uygulamada birleştirebilirsiniz. Örneğin, JavaScript'te kullanıcı arabiriminizi oluşturabilir ve C++ bileşeninde işlem açısından yoğun uygulama mantığını gerçekleştirebilirsiniz. Bu hesaplama açısından yoğun işlemleri arka planda gerçekleştirebilme özelliği, kullanıcı arabiriminizin yanıt verme hızını korumada önemli bir faktördür.
task
Sınıfı C++'a özgü olduğundan, zaman uyumsuz işlemleri diğer bileşenlere (C++ dışındaki dillerde yazılabilir) iletmek için bir Windows Çalışma Zamanı arabirimi kullanmanız gerekir. Windows Çalışma Zamanı, zaman uyumsuz işlemleri temsil etmek için kullanabileceğiniz dört arabirim sağlar:
Windows::Foundation::IAsyncAction
Zaman uyumsuz bir eylemi temsil eder.
Windows::Foundation::IAsyncActionWithProgress<TProgress>
İlerleme durumunu bildiren zaman uyumsuz bir eylemi temsil eder.
Windows::Foundation::IAsyncOperation<TResult>
Sonuç döndüren asenkron bir işlemi temsil eder.
Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress>
Bir sonuç döndüren ve ilerleme durumunu bildiren zaman uyumsuz bir işlemi temsil eder.
Eylemin belirtilmesi, zaman uyumsuz görevin bir değer üretmediği anlamına gelir (döndüren void
bir işlevi düşünün).
bir işlemin belirtilmesi, zaman uyumsuz görevin bir değer ürettiği anlamına gelir.
İlerleme durumu, görevin ilerleme iletilerini çağırana bildirebileceği anlamına gelir. JavaScript, .NET Framework ve Visual C++ her biri ABI sınırında kullanılmak üzere bu arabirimlerin örneklerini oluşturmak için kendi yolunu sağlar. Visual C++ için PPL eşzamanlılık::create_async işlevini sağlar. Bu işlev, görevin tamamlanmasını temsil eden zaman uyumsuz bir Windows Çalışma Zamanı eylemi veya işlemi oluşturur. Fonksiyon create_async
işlevsel bir görev (genellikle lambda ifadesi) alır, ve dahili olarak bir task
nesne oluşturur ve bu görevi dört eşzamansız Windows Runtime arabiriminden birine sarar.
Uyarı
Yalnızca başka bir dilden veya başka bir Windows Çalışma Zamanı bileşeninden erişilebilen işlevler oluşturmanız gerektiğinde kullanın create_async
. İşlemin aynı bileşendeki task
C++ kodu tarafından hem üretildiğini hem de kullanıldığını bildiğinizde sınıfını doğrudan kullanın.
create_async
dönüş tipi, bağımsız değişkenlerinin türüne göre belirlenir. Örneğin, işleviniz bir değer döndürmez ve ilerleme durumunu bildirmezse, create_async
IAsyncAction
döndürür. İş işleviniz bir değer döndürmez ve ilerleme durumunu bildirirse, create_async
IAsyncActionWithProgress
geri döner. İlerleme durumunu bildirmek için, iş işlevinizin parametresi olarak bir eşzamanlılık::p rogress_reporter nesnesi sağlayın. İlerleme durumunu raporlama özelliği, hangi çalışma miktarının gerçekleştirildiğini ve hangi tutarın hala kaldığını (örneğin, yüzde olarak) raporlamanızı sağlar. Ayrıca sonuçları kullanılabilir duruma geldikçe raporlamanıza da olanak tanır.
IAsyncAction
, IAsyncActionWithProgress<TProgress>
, IAsyncOperation<TResult>
ve IAsyncActionOperationWithProgress<TProgress, TProgress>
arabirimlerinin her birinde zaman uyumsuz işlemi iptal etmenizi sağlayan bir Cancel
yöntem sağlanır. sınıfı iptal task
belirteçleriyle çalışır. çalışmayı iptal etmek için bir iptal belirteci kullandığınızda, çalışma zamanı bu belirtece abone olan yeni çalışmayı başlatmaz. Zaten etkin olan çalışma iptal belirtecini izleyebilir ve uygun bir zamanda durabilir. Bu mekanizma , PPL'deki İptal belgesinde daha ayrıntılı olarak açıklanmıştır. Görev iptalini Windows Çalışma Zamanı Cancel
yöntemleriyle iki şekilde bağlayabilirsiniz. İlk olarak, bir create_async
nesnesi almak için 'ye ilettiğiniz işlevi tanımlayabilirsiniz. Yöntemi Cancel
çağrıldığında, bu iptal belirteci iptal edilir ve normal iptal kuralları, task
çağrısını destekleyen create_async
temel nesne için geçerlidir. Bir cancellation_token
nesne sağlamazsanız, temel alınan task
nesne örtük olarak bir nesne tanımlar. İş işlevinizde iptale birlikte yanıt vermeniz gerektiğinde bir cancellation_token
nesne tanımlayın.
Örnek: C++ ve XAML ile Bir Windows Çalışma Zamanı Uygulamasında Yürütmeyi Denetleme bölümü, özel bir Windows Runtime C++ bileşeni kullanan C# ve XAML ile Evrensel Windows Platformu (UWP) uygulamasında iptal işleminin nasıl gerçekleştirildiğini gösteren bir örnek gösterir.
Uyarı
Görev devamlılıkları zincirinde, her zaman durumu temizleyin ve iptal belirteci iptal edildiğinde concurrency::cancel_current_task fonksiyonunu çağırın. çağrısı yapmak yerine erken dönerseniz, işlem iptal edilen durum yerine tamamlanmış duruma geçer.
Aşağıdaki tabloda, uygulamanızda zaman uyumsuz işlemleri tanımlamak için kullanabileceğiniz birleşimler özetlemektedir.
Bu Windows Çalışma Zamanı arabirimini oluşturmak için | Bu türü şu kaynaktan döndür: create_async |
Örtük iptal belirteci kullanmak için bu parametre türlerini iş işlevinize geçirin | Açık bir iptal belirteci kullanmak için bu parametre türlerini iş işlevinize geçirin |
---|---|---|---|
IAsyncAction |
void veya task<void> |
(yok) | (cancellation_token ) |
IAsyncActionWithProgress<TProgress> |
void veya task<void> |
(progress_reporter ) |
(progress_reporter , cancellation_token ) |
IAsyncOperation<TResult> |
T veya task<T> |
(yok) | (cancellation_token ) |
IAsyncActionOperationWithProgress<TProgress, TProgress> |
T veya task<T> |
(progress_reporter ) |
(progress_reporter , cancellation_token ) |
İşleve geçirdiğiniz task
iş işlevinden bir create_async
değer veya nesne döndürebilirsiniz. Bu çeşitlemeler farklı davranışlar üretir. Bir değer döndürdüğünüzde, işlev arka planda çalıştırılabilmesi için bir task
içine sarmalanır. Ayrıca, temel alınan task
belirsiz bir iptal belirteci kullanır. Buna karşılık, bir task
nesne döndürürseniz, iş işlevi zaman uyumlu olarak çalışır. Bu nedenle, bir task
nesne döndürürseniz, uygulamanızın yanıt vermeye devam etmesini sağlamak için iş işlevinizdeki uzun işlemlerin de görev olarak çalıştığından emin olun. Ayrıca, temel alınan task
örtük bir iptal belirteci kullanmaz. Bu nedenle, cancellation_token
öğesinden task
nesne döndürdüğünüzde iptal için desteğe ihtiyacınız varsa, create_async
nesnesi almak için işlevinizi tanımlamanız gerekir.
Aşağıdaki örnekte, başka bir Windows Çalışma Zamanı bileşeni tarafından kullanılabilecek bir IAsyncAction
nesne oluşturmanın çeşitli yolları gösterilmektedir.
// 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.
});
});
Örnek: C++ Windows Çalışma Zamanı Bileşeni Oluşturma ve C# ile Kullanma
Kullanıcı arabirimini tanımlamak için XAML ve C# kullanan bir uygulamayı ve yoğun işlem gerektiren işlemler gerçekleştirmek için bir C++ Windows Çalışma Zamanı bileşenini düşünün. Bu örnekte, C++ bileşeni belirli bir aralıktaki sayıların asal olduğunu hesaplar. Dört Windows Çalışma Zamanı zaman uyumsuz görev arabirimi arasındaki farkları göstermek için, Visual Studio'da boş bir Çözüm oluşturup bunu Primes
adlandırarak başlatın. Ardından çözüme bir Windows Çalışma Zamanı Bileşeni projesi ekleyin ve adını ekleyin PrimesLibrary
. Oluşturulan C++ üst bilgi dosyasına aşağıdaki kodu ekleyin (bu örnek Class1.h'yi Primes.h olarak yeniden adlandırır). Her public
yöntem, dört zaman uyumsuz arabirimden birini tanımlar. Değer döndüren yöntemler bir Windows::Foundation::Collections::IVector<int> nesnesi döndürür. İlerleme durumunu bildiren yöntemler, tamamlanan genel çalışma yüzdesini tanımlayan değerler üretir double
.
#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);
};
}
Uyarı
Kural gereği, Windows Çalışma Zamanı'ndaki zaman uyumsuz yöntem adları genellikle "Async" ile biter.
Oluşturulan C++ kaynak dosyasına aşağıdaki kodu ekleyin (bu örnek Class1.cpp Primes.cpp olarak yeniden adlandırır). İşlev, is_prime
girişinin asal olup olmadığını belirler. Kalan yöntemler sınıfını Primes
uygular. Her create_async
çağrısı, çağrıldığı metotla uyumlu bir imza kullanır. Örneğin, Primes::ComputePrimesAsync
IAsyncAction
döndürdüğünden, create_async
sağlanan işlev bir değer döndürmez ve bir progress_reporter
nesneyi parametre olarak almaz.
// 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;
});
}
Her yöntem önce giriş parametrelerinin negatif olmamasını sağlamak için doğrulama gerçekleştirir. Bir giriş değeri negatifse, yöntemi Platform::InvalidArgumentException oluşturur. Hata işleme bu bölümün ilerleyen bölümlerinde açıklanmıştır.
Bu yöntemleri bir UWP uygulamasından kullanmak için Visual C# Boş Uygulama (XAML) şablonunu kullanarak Visual Studio çözümüne ikinci bir proje ekleyin. Bu örnekte projeyi Primes
olarak adlandırabilirsiniz. Ardından, Primes
projesinden PrimesLibrary
projesine bir başvuru ekleyin.
MainPage.xaml'e aşağıdaki kodu ekleyin. Bu kod, C++ bileşenini çağırabilmeniz ve sonuçları görüntüleyebilmeniz için kullanıcı arabirimini tanımlar.
<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>
MainPage.xaml dosyasında sınıfına MainPage
aşağıdaki kodu ekleyin. Bu kod bir Primes
nesneyi ve düğme olay işleyicilerini tanımlar.
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();
}
Bu yöntemler, zaman uyumsuz işlemler tamamlandıktan sonra kullanıcı arabirimini güncelleştirmek için async
ve await
anahtar sözcüklerini kullanır. UWP uygulamalarında zaman uyumsuz kodlama hakkında bilgi için bkz: İş parçacığı oluşturma ve zaman uyumsuz programlama.
getPrimesCancellation
ve cancelGetPrimes
yöntemleri birlikte çalışarak kullanıcının işlemi iptal edebilmesini sağlar. Kullanıcı İptal düğmesini seçtiğinde cancelGetPrimes
, yöntemi işlemi iptal etmek için IAsyncOperationWithProgress<TResult, TProgress>::Cancel çağrıları gerçekleştirir. Alttaki asenkron işlemi yöneten Eşzamanlı Çalışma Zamanı, iptal işleminin tamamlandığını bildirmek için Windows Çalışma Zamanı tarafından yakalanan bir iç özel durum türü oluşturur. İptal modeli hakkında daha fazla bilgi için bkz. İptal.
Önemli
PPL'nin işlemi iptal ettiğini Windows Çalışma Zamanı'na doğru şekilde raporlamasını sağlamak için, bu iç özel durum türünü yakalamayın. Bu, tüm özel durumları (catch (...)
) yakalamamanız gerektiği anlamına gelir. Tüm özel durumları yakalamanız gerekiyorsa, Windows Çalışma Zamanı'nın iptal işlemini tamamlayabilmesini sağlamak için özel durumu yeniden fırlatın.
Aşağıdaki çizimde, her seçenek seçildikten sonra Primes
uygulaması gösterilmektedir.
Diğer diller tarafından kullanılabilecek zaman uyumsuz görevler oluşturmak için create_async
kullanan bir örnek arıyorsanız, Bing Haritalar Gezi İyileştiricisi örneğinde C++ kullanma bölümüne bakın.
Yürütme İş Parçacığını Denetleme
Windows Çalışma Zamanı COM iş parçacığı modelini kullanır. Bu modelde nesneler, eşitlemelerini nasıl işlediklerine bağlı olarak farklı dairelerde barındırılır. İş parçacığı güvenli nesneler, çok iş parçacıklı dairede (MTA) barındırılır. Tek bir iş parçacığı tarafından erişilmesi gereken nesneler, tek iş parçacıklı bir modelde (STA) barındırılır.
Kullanıcı arabirimi olan bir uygulamada, ASTA (Application STA) iş parçacığı pencere iletilerinin pompalanmasından sorumludur ve işlemde STA tarafından barındırılan kullanıcı arabirimi denetimlerini güncelleştirebilen tek iş parçacığıdır. Bunun iki sonucu vardır. İlk olarak, uygulamanın yanıt vermeye devam edebilmesi için tüm CPU yoğunluklu ve G/Ç işlemleri ASTA iş parçacığında çalıştırılmamalıdır. İkinci olarak, arka plan iş parçacıklarından gelen sonuçlar, kullanıcı arabirimini güncellemek için ASTA'ya aktarılmalıdır. C++ UWP uygulamasında MainPage
ve diğer XAML sayfalarının tümü ATSA üzerinde çalışır. Bu nedenle, ASTA'da bildirilen görev devamlılıkları varsayılan olarak orada çalıştırılır, böylece denetimleri doğrudan devamlılık gövdesinde güncelleştirebilirsiniz. Ancak, bir görevi başka bir göreve iç içe yerleştirdiğinizde, bu iç içe görevdeki tüm devamlılıklar MTA'da çalıştırılır. Bu nedenle, bu devamların hangi bağlamda çalıştırılacağını açıkça belirtmeniz gerekip gerekmediğine dikkat etmeniz gerekir.
Asenkron bir işlemden oluşturulan bir görev, iş parçacığı ayrıntılarını göz ardı etmenizi sağlayan özel semantikler kullanır. Bir işlem arka plan iş parçacığında çalıştırılabilir (veya bir iş parçacığı tarafından hiç yedeklenmeyebilir), ancak devamlılık işlemlerini başlatan dairede (başka bir deyişle, adlı task::then
daireden) çalıştırılması varsayılan olarak garanti edilir. Bir devamlılığın yürütme bağlamını denetlemek için eşzamanlılık::task_continuation_context sınıfını kullanabilirsiniz. Nesneleri oluşturmak task_continuation_context
için şu statik yardımcı yöntemleri kullanın:
Devamın arka plan iş parçacığında çalıştırılacağını belirtmek için eşzamanlılık::task_continuation_context::use_arbitrary kullanın.
Devamlılığın adlı iş parçacığında çalıştırılacağını belirtmek için
task::then
kullanın.
Bir task_continuation_context
nesnesini, task::then yöntemine geçirerek devamın yürütme bağlamını açıkça kontrol edebilir veya görevi başka bir ortama geçirebilir ve ardından yürütme bağlamını örtük olarak kontrol etmek için task::then
yöntemini çağırabilirsiniz.
Önemli
UWP uygulamalarının ana ui iş parçacığı STA altında çalıştığından, bu STA üzerinde varsayılan olarak oluşturduğunuz devamlılıklar STA üzerinde çalıştırılır. Buna göre, MTA'da oluşturduğunuz devamlılıklar MTA üzerinde çalıştırılır.
Aşağıdaki bölümde, diskten dosya okuyan, bu dosyadaki en yaygın sözcükleri bulan ve ardından sonuçları kullanıcı arabiriminde gösteren bir uygulama gösterilmektedir. Son işlem olan kullanıcı arabirimini güncelleştirme işlemi, kullanıcı arabirimi iş parçacığında gerçekleşir.
Önemli
Bu davranış UWP uygulamalarına özgüdür. Masaüstü uygulamaları için devamlılıkların nerede çalıştığını denetlemezsiniz. Bunun yerine zamanlayıcı, her devamlılığı çalıştıracak bir çalışan iş parçacığı seçer.
Önemli
Eşzamanlılık::task::wait dosyasını STA üzerinde çalışan bir devamlılığın gövdesinde çağırmayın. Aksi takdirde çalışma zamanı eşzamanlılık::invalid_operation oluşturur çünkü bu yöntem geçerli iş parçacığını engeller ve uygulamanın yanıt vermemeye başlamasına neden olabilir. Ancak, öncül görevin sonucunu görev tabanlı bir devamlılıkta almak için eşzamanlılık::task::get yöntemini çağırabilirsiniz.
Örnek: C++ ve XAML ile Bir Windows Çalışma Zamanı Uygulamasında Yürütmeyi Denetleme
Bir dosyayı diskten okuyan, bu dosyadaki en yaygın sözcükleri bulan ve ardından sonuçları kullanıcı arabiriminde gösteren bir C++ XAML uygulaması düşünün. Bu uygulamayı oluşturmak için, Visual Studio'da bir Boş Uygulama (Evrensel Windows) projesi oluşturup adını CommonWords
vererek uygulamasını başlatın. Uygulama bildiriminizde, uygulamanın Belgeler klasörüne erişmesini sağlamak için Belge Kitaplığı özelliğini belirtin. Ayrıca, uygulama bildiriminin bildirimler bölümüne Text (.txt) dosya türünü ekleyin. Uygulama özellikleri ve bildirimleri hakkında daha fazla bilgi için bkz . Windows uygulamalarını paketleme, dağıtma ve sorgulama.
MainPage.xaml dosyasındaki Grid
öğesini, bir ProgressRing
öğesi ve bir TextBlock
öğesi içerecek şekilde güncelleştirin. , ProgressRing
işlemin devam ettiğini gösterir ve TextBlock
hesaplamanın sonuçlarını gösterir.
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<ProgressRing x:Name="Progress"/>
<TextBlock x:Name="Results" FontSize="16"/>
</Grid>
Aşağıdaki #include
deyimleri pch.h'ye ekleyin.
#include <sstream>
#include <ppltasks.h>
#include <concurrent_unordered_map.h>
Sınıfına (MainPage.h) aşağıdaki yöntem bildirimlerini MainPage
ekleyin.
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);
Aşağıdaki using
deyimlerini MainPage.cpp'e ekleyin.
using namespace concurrency;
using namespace std;
using namespace Windows::Storage;
using namespace Windows::Storage::Streams;
MainPage.cpp dosyasında MainPage::MakeWordList
, MainPage::FindCommonWords
ve MainPage::ShowResults
yöntemlerini uygulayın.
MainPage::MakeWordList
ve MainPage::FindCommonWords
işlem açısından yoğun işlemler gerçekleştirir. yöntemi, MainPage::ShowResults
kullanıcı arabirimindeki hesaplamanın sonucunu görüntüler.
// 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());
}
Oluşturucuyu MainPage
değiştirerek kullanıcı arabiriminde Homer'ın İlyada adlı kitabındaki ortak sözcükleri görüntüleyen bir devamlılık görevleri zinciri oluşturun. Metni tek tek sözcüklere bölen ve ortak sözcükleri bulan ilk iki devamlılık görevi zaman alabilir ve bu nedenle açıkça arka planda çalışacak şekilde ayarlanır. Kullanıcı arabirimini güncelleştiren son devamlılık görevi, devam bağlamı belirtmez ve bu nedenle apartman iş parçacığı oluşturma kurallarını izler.
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.
});
}
Uyarı
Bu örnek, yürütme bağlamlarının nasıl belirtileceğini ve bir devamlılık zincirinin nasıl oluşturılacağını gösterir. Varsayılan olarak, zaman uyumsuz bir işlemden oluşturulan bir görevin devamlılıklarını adlı task::then
dairede çalıştırdığını hatırlayın. Bu nedenle, bu örnek kullanıcı arabirimini içermeyen işlemlerin bir arka plan iş parçacığında gerçekleştirileceğini belirtmek için kullanır task_continuation_context::use_arbitrary
.
Aşağıdaki çizimde uygulamanın sonuçları gösterilmektedir CommonWords
.
Bu örnekte, destekleyen task
nesneler örtük bir iptal belirteci kullandığından create_async
iptali desteklemek mümkündür. Görevlerinizin işbirlikçi bir şekilde iptale yanıt vermesi gerekiyorsa cancellation_token
nesnesi alacak şekilde işlevinizi tanımlayın. PPL'de iptal hakkında daha fazla bilgi için bkz. PPL'de iptal etme