Aracılığıyla paylaş


UWP Uygulamaları için C++ Uygulamasında Zaman Uyumsuz İşlemler Oluşturma

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 zaman uyumsuz Windows Çalışma Zamanı işlemleri zincirlerinin nasıl tüketilip oluşturulacağı öğretilir. 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.

Dekont

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ılabilir) tarafından kullanılabilecek zaman uyumsuz 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.

  • İç zaman uyumsuz işlemlerin iptal edebilmesi 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> veya task<void>) döndüren bir iş işlevi, adlı create_asyncbağlamda zaman uyumlu bir şekilde çalışır. Rastgele bir bağlamda döndüren T veya void çalıştıran bir iş işlevi.

  • 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ı 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ılmış olabilir) iletmek için 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 zaman uyumsuz 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 voidbir 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 Windows Çalışma Zamanı zaman uyumsuz bir eylem veya işlem oluşturur. İşlev create_async bir iş işlevi (genellikle lambda ifadesi) alır, dahili olarak bir task nesne oluşturur ve bu görevi zaman uyumsuz dört Windows Çalışma Zamanı arabiriminden birinde sarmalar.

Dekont

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ıncreate_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.

dönüş türü create_async , bağımsız değişkenlerinin türüne göre belirlenir. Örneğin, iş işleviniz bir değer döndürmez ve ilerleme durumunu bildirmezse döndürür create_asyncIAsyncAction. İş işleviniz bir değer döndürmez ve ilerleme durumunu bildirirse döndürür create_asyncIAsyncActionWithProgress. İ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 biri zaman uyumsuz işlemi iptal etmenizi sağlayan bir Cancel metodu sunar. 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 ne zaman durdurabilir. 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 eşzamanlılık::cancellation_token nesnesi almak için geçirdiğiniz create_async iş işlevini tanımlayabilirsiniz. Yöntemi çağrıldığındaCancel, bu iptal belirteci iptal edilir ve normal iptal kuralları çağrıyı destekleyen create_async temel nesne task için geçerlidir. Bir cancellation_token nesnesi belirtmezseniz, temel alınan task nesnesi örtük olarak bir nesne tanımlar. Çalışma işlevinizde bir iptali işbirliği halinde olarak yanıtlamanız gerektiğinde bir cancellation_token nesnesi tanımlayın. Örnek: C++ ve XAML ile bir Windows Çalışma Zamanı Uygulamasında Yürütmeyi Denetleme bölümünde, C# ve XAML ile özel bir Windows Çalışma Zamanı C++ bileşeni kullanan bir Evrensel Windows Platformu (UWP) uygulamasında iptal işleminin nasıl gerçekleştirildiğini gösteren bir örnek gösterilmektedir.

Uyarı

Görev devamlılığı zincirinde, her zaman durumu temizleyin ve iptal belirteci iptal edildiğinde eşzamanlılık::cancel_current_task çağrısı yapın. çağrısı cancel_current_taskyerine erken dönerseniz, işlem iptal edilen durum yerine tamamlanmış duruma geçirilir.

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 create_async iş işlevinden bir task değer veya nesne döndürebilirsiniz. Bu çeşitlemeler farklı davranışlar üretir. Bir değer döndürdüğünüzde, iş işlevi bir arka plan iş parçacığında çalıştırılabilmesi için bir task içine sarmalanır. Ayrıca, temel alınan task örtük 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, öğesinden create_asyncbir cancellation_token nesne döndürürken task iptal için destek gerekiyorsa, nesne almak için iş 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'den 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şeni 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 Primesadlandırarak başlatın. Ardından çözüme bir Windows Çalışma Zamanı Bileşeni projesi ekleyin ve adını ekleyinPrimesLibrary. 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);
    };
}

Dekont

Kural gereği, Windows Çalışma Zamanı zaman uyumsuz yöntem adları genellikle "Async" ile biter.

Oluşturulan C++ kaynak dosyasına aşağıdaki kodu ekleyin (bu örnek Class1.cpp dosyasını 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. çağrısının create_async her biri, çağrıldığı yöntemle uyumlu bir imza kullanır. Örneğin, döndürdüğünden Primes::ComputePrimesAsyncIAsyncActioncreate_async, sağlanan iş işlevi bir değer döndürmez ve parametresi olarak bir progress_reporter nesne 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 Primesolarak adlandırabilirsiniz. Ardından, projeden Primes projeye bir başvuru PrimesLibrary 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 ve await anahtar sözcüklerini kullanırasync. 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. Temel alınan zaman uyumsuz işlemi yöneten Eşzamanlılık Ç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 Windows Çalışma Zamanı 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ı iptal işlemini tamamlayabilmesini sağlamak için özel durumu yeniden yükleyin.

Aşağıdaki çizimde Primes , her seçenek seçildikten sonra uygulama gösterilmektedir.

Windows Runtime Primes app.

Diğer diller tarafından kullanılabilecek zaman uyumsuz görevler oluşturmak için kullanan create_async bir örnek için bkz. Bing Haritalar Trip Optimizer örneğinde C++ kullanma.

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 dairede (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üncelleştirmek için ASTA'ya geri sıralanmalı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 devamlılıkların hangi bağlamda çalıştırılacağını açıkça belirtip belirtmeyeceğinize dikkat etmeniz gerekir.

gibi IAsyncOperation<TResult>zaman uyumsuz bir işlemden oluşturulan bir görev, iş parçacığı ayrıntılarını yoksaymanıza yardımcı olabilecek ö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::thendaireden) ç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:

  • Devamlılığı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ı task::theniş parçacığında çalıştırılacağını belirtmek için concurrency::task_continuation_context::use_current kullanın.

Bir nesneyi göreve geçirebilirsiniztask_continuation_context::then yöntemiyle devamlılık yürütme bağlamını açıkça denetleyebilirsiniz veya görevi başka bir daireye geçirebilir ve ardından yürütme bağlamını task::then örtük olarak denetlemek için 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 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ı CommonWordsvererek 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 Metin (.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.

Grid MainPage.xaml dosyasındaki öğesini bir ProgressRing öğe ve öğe içerecek şekilde TextBlock 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);

MainPage.cpp'ye aşağıdaki using deyimleri ekleyin.

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

MainPage.cpp dosyasında , MainPage::FindCommonWordsve MainPage::ShowResults yöntemlerini uygulayınMainPage::MakeWordList. 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.
    });
}

Dekont

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::thendairede ç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 .

Windows Runtime CommonWords app.

Bu örnekte, destekleyen create_async nesneler örtük bir iptal belirteci kullandığından task iptali desteklemek mümkündür. Görevlerinizin işbirlikçi bir cancellation_token şekilde iptale yanıt vermesi gerekiyorsa nesne almak için iş işlevinizi tanımlayın. PPL'de iptal hakkında daha fazla bilgi için bkz. PPL'de iptal etme

Ayrıca bkz.

Eşzamanlılık Çalışma Zamanı