Aracılığıyla paylaş


Windows Mağazası Uygulamaları için C++ Uygulamasında Zaman Uyumsuz İşlemler Oluşturma

Bu belge, bir Windows Mağazası uygulaması içinde asenkron işlemler üretmek için Eşzamanlılık Çalışma Zamanı kullandığınız zaman akılda tutulması gereken önemli noktalar bazılarını açıklanmaktadır.

Asenkron programlama kullanımını Windows Mağazası uygulama modeli içinde temel bileşendir çünkü uygulamalar kullanıcı girişine yanıt verilmesini sağlar. Uzun sürecek bir iş parçacığını UI iş parçacığını engellemeden başlatabilirsiniz ve görevin sonuçlarını daha sonra alabilirsiniz. Ayrıca görevleri iptal edebilir ve arka planda çalışan görevlerin ilerleme bildirimleri alabilirsiniz. C++'ta Asenkron programlama belgesi Windows Mağazası uygulamaları oluşturmak için Visual C++'ta kullanılabilir asenkron modele genel bir bakış sağlar. Bu belge, asenkron Windows Çalışma Zamanı işlemlerinin hem tüketen hem de oluşturan zincirlerini nasıl oluşturulduğunu öğretir. Bu bölümde Eşzamanlılık Çalışma Zamanı'nı başka Windows Çalışma Zamanı bileşeni tarafından tüketilen asenkron işlemleri oluşturmak için nasıl kullanılacağını ve asenkron iş denetimi nasıl gerçekleştirilir açıklar. Ayrıca şunu da okumayı dikkate alın: Hilo içinde Asenkron programlama modelleri ve ipuçları (C++ ve XAML kullanarak Windows Mağazası uygulamaları) asenkron işlemler uygulamak için Hilo içinde Eşzamanlılık Çalışma Zamanı nasıl kullanılacağını öğrenmek için bir Windows Mağazası C++ ve XAML kullanarak uygulama.

Not

Paralel Modeller Kitaplığı (PMK) ve Zaman uyumsuz aracıları kitaplığı, bir Windows Mağazası uygulaması içinde kullanabilirsiniz.Ancak, Görev Zamanlayıcısı'nı veya Kaynak Yöneticisi'ni kullanamazsınız.Bu belge bir masaüstü uygulamasında olmayan ve yalnızca bir Windows Mağazası uygulaması için kullanılabilir Eşzamanlılık Çalışma Zamanı'nın sağladığı ek özellikleri açıklar.

Önemli noktalar

  • Diğer bileşenler tarafından kullanılan (C++ dışındaki dillerde yazılmış olabilir) asenkron işlemler oluşturmak için concurrency::create_async kullanın.

  • Asenkron işlemlerinizi çağıran bileşenlere ilerleme bildirimlerini raporlamak için concurrency::progress_reporter kullanın.

  • İptal etmek için dahili asenkron işlemlerini etkinleştirmek için İptal belirteci kullanın.

  • create_async işlevi kendisine geçirilen iş fonksiyonunun dönüş türüne bağlıdır. Bir görev döndüren bir iş fonksiyonu (hem task<T> hem de task<void>) create_async adı verilen bağlamda senkron olarak çalışır. Bir T veya void döndüren fonksiyon rastgele bir içerikte çalışır.

  • birbiri ardına çalışan görevler zinciri oluşturmak için concurrency::task::then metodunu kullanabilirsiniz. Bir Windows Mağazası uygulaması içinde, bir görevin devamlılığı için varsayılan içerik görevin nasıl inşa edildiğine bağlıdır. Eğer görev asenkron bir eylemi görev yapıcısına ileterek veya bir asenkron eylem döndüren bir lambda ifadesi geçirerek oluşturulduysa, daha sonra bu görevin tüm devamlılığının varsayılan içeriği geçerli içeriği olur. Eğer görev asenkron bir eylemden oluşturulmamışsa, o zaman rastgele bir bağlam görevin devamlılığı için varsayılan olarak kullanılır. Varsayılan içeriği concurrency::task_continuation_context sınıfı ile geçersiz kılabilirsiniz/override edebilirsiniz.

Bu belgede

  • Asenkron İşlemler Oluşturma

  • Örnek: C++ Windows Çalışma Zamanı Bileşeni Oluşturma

  • Yürütme İş Parçacığını Denetleme

  • Örnek: C++ ve XAML ile Windows Mağazası Uygulaması Yürütme Denetleme

Asenkron İşlemler Oluşturma

Önceki görevi tamamladığında, çalışan ek görevlerin yanı sıra arka plan görevleri tanımlamak için görevi ve devamlılık modelini Paralel Model Kitaplığı (PMK) içinde kullanabilirsiniz. Bu fonksiyonellik 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 paralellik (eşzamanlılık çalışma zamanı).

Windows Çalışma Zamanı öğesi, yalnızca özel bir işletim sistemi ortamında çalışan Windows Mağazası uygulamalar oluşturmak için kullanabileceğiniz bir programlama arabirimidir. Bu tür uygulamalar yetkili fonksiyonlar, veri türleri ve aygıtları kullanırlar ve Windows Mağazası öğesinden dağıtılırlar. Windows Çalışma Zamanı öğesi Uygulama İkili Arabirimi (ABI) Tarafından temsil edilir. ABI Windows Çalışma Zamanı API'lerini Visual C++ gibi programlama dillerine kullanılabilir kılan belli başlı bir ikili sözleşmedir.

Windows Çalışma Zamanı kullanarak, çeşitli programlama dillerinde en iyi özellikleri kullanabilir ve bunları bir uygulamada birleştirebilirsiniz. Örneğin, kullanıcı arabiriminizi JavaScript içinde oluşturabilir ve hesaplama açısından yoğun uygulama mantığını C++ bileşeni içinde gerçekleştirebilirsiniz. Arka planda bu hesaplama açısından yoğun işlemleri gerçekleştirme kullanıcı arabirimini tepkili tutmak için önemli bir yetenektir. Çünkü task sınıfı C++'a özgüdür, diğer bileşenleri asenkron işlemlerle iletişimini kurmak için bir Windows Çalışma Zamanı arabirimi kullanmalısınız (C++ dışındaki dillerde yazılmış olabilir). Windows Çalışma Zamanı asenkron işlemleri göstermek için kullanabileceğiniz dört arabirim sağlar:

Bir eylem öğesinin kavramı, asenkron bir görev bir değer üretmez anlamına gelir (bir void döndüren fonksiyon düşüncesi). Bir işlem öğesinin kavramı asenkron görev bir değer üretir anlamına gelir. Bir ilerleme durumu öğesi kavramı görev ilerleme durumu iletilerini çağrıyı yapana bildirebilir anlamına gelir. ABI sınırı boyunca bu arabirimlerin kullanım örneklerini oluşturmak için JavaScript, .NET Framework ve Visual C++ her biri kendi yolunu sağlar. Visual C++ için Eşzamanlılık Çalışma Zamanı concurrency::create_async fonksiyonunu sağlar. Bu fonksiyon bir görevin tamamlanmasını gösteren bir Windows Çalışma Zamanı asenkron eylem veya işlem oluşturur. create_async fonksiyonu bir iş fonksiyonu alır (genellikle bir lambda ifadesi), dahili olarak bir task nesne oluşturur ve dört asenkron Windows Çalışma Zamanı arabirimden birinin içindeki görevi sarar.

Not

create_async öğesini yalnızca başka bir dilden veya başka Windows Çalışma Zamanı bileşeninden erişmek zorunda olduğunuz zaman kullanın.task sınıfını, işlemi aynı bileşen içindeki C++ kodu tarafından hem üretilen hem de tüketilen olduğunu biliyorsanız doğrudan kullanın.

create_async öğesinin dönüş türü argümanlarının türüne göre belirlenir. Örneğin, iş fonksiyonunuz bir değer döndürmüyor ve ilerleme durumu bildirmiyorsa, create_async öğesi IAsyncAction dönderir. Eğer iş fonksiyonunuz bir değer döndürmüyor ve ayrıca ilerleme durumu raporluyorsa create_async öğesi IAsyncActionWithProgress dönderir. İlerleme durumu raporlamak için iş fonksiyonunuz için parametre olarak bir concurrency::progress_reporter nesnesi sağlayın. İlerleme durumu raporlama yeteneği size işin ne kadar miktarının yapıldığını ve daha ne kadarının yapılmadığını raporlamanızı sağlar (örneğin, yüzde olarak). Ayrıca, kullanılabilir olduklarında, sonuçları raporlamanızı sağlar.

IAsyncAction, IAsyncActionWithProgress<TProgress>, IAsyncOperation<TResult>, ve IAsyncActionOperationWithProgress<TProgress, TProgress> arabirimlerinin her biri asenkron işlemleri iptal edebileceğiniz bir Cancel metot sağlar. task sınıfı iptal belirteçleri ile çalışır. İşi iptal etmek için bir iptal belirteci kullandığınızda, çalışma zamanı bu belirteç için abone olan yeni iş başlatmaz. Zaten etkin olan iş, iptalini izleyebilir ve mümkün olduğunda durdurur. Bu mekanizma belgede daha ayrıntılı bir şekilde açıklanmaktadır ppl iptali. Görev iptal etme işlemine Windows Çalışma Zamanı Cancel metoduyla iki şekilde bağlantı kurabilirsiniz. İlk olarak, create_async öğesine bir concurrency::cancellation_token nesnesi almak için geçen iş fonksiyonu tanımlayabilirsiniz. Cancel yöntemi çağrıldığında, bu iptal belirteci iptal edilir ve task öğesi olan create_async çağrısı destekleyen temel nesnenin iptal kuralları uygulanır. Eğer bir cancellation_token nesnesi sağlamazsanız, temel task nesnesi dolaylı olarak bir tane tanımlar. İş fonksiyonunuz içinde iptal etmeyi iş birliği yaparak cevaplamak için bir cancellation_token nesnesi tanımlayın. Bölüm Örnek: C++ ve XAML ile Windows Mağazası Uygulama Kontrol İşlemi Yürütme bir C# ve XAML ile bir Windows Mağazası uygulaması içinde, özel bir Windows Çalışma Zamanı C++ bileşeni kullanan uygulaması içinde iptal işlemini nasıl gerçekleştireceği hakkında bir örnek gösterir.

Uyarı

Bir görev devamlılığı zincirinde, her zaman durumu temizler ve sonra concurrency::cancel_current_task öğesini çağırır concurrency::is_task_cancellation_requested öğesi true döndürdüğü zaman.Eğer cancel_current_task arama yerine erkenden döndürürseniz, işlem geçişimleri iptal durumu yerine tamamlandı durumuna geçer.

Aşağıdaki tablo, uygulamanız içinde asenkron işlem tanımlamak için kullanabileceğiniz kombinasyonlarını özetler.

Bu Windows Çalışma Zamanı arabirimi oluşturmak için

Bu türü create_async'den döndürün

Bir örtülü iptal belirteci kullanmak için çalışma fonksiyonunuza bu parametreleri geçirin.

Bir açık iptal belirteci kullanmak için çalışma fonksiyonunuza bu parametreleri 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)

Bir değer veya task nesne, create_async fonksiyonuna geçirdiğiniz iş fonksiyonunuzdan bir nesne döndürebilirsiniz. Bu farklılıklar farklı davranışlar üretir. Bir değer döndürdüğünüz zaman, iş fonksiyonu bir task görev içine kaydırılır böylece bir arka plan iş parçacığı üzerinde çalışabilir. Buna ek olarak, temel task bir örtülü iptal belirteci kullanır. Buna karşılık, eğer bir task nesnesi dönerseniz, iş fonksiyonu senkronize çalışır. Bu nedenle, eğer bir task nesne döndürürseniz, iş fonksiyonunuzun içindeki uzun işlemlerin uygulamanızı yanıt verebilir durumda olmasını sağlamak için ayrıca görev olarak çalıştığından emin olun. Buna ek olarak, temel task bir örtülü iptal belirteci kullanmaz. Bu nedenle, iş fonksiyonunuzu bir cancellation_token nesnesi almak için eğer bir task nesne, create_async öğesinden bir nesne, döndürdüğünüz zaman iptal etme için desteğe ihtiyacınız olursa, tanımlamaya ihtiyacınız vardır.

Aşağıdaki örnek, bir IAsyncAction nesne, başka bir Windows Çalışma Zamanı bileşen tarafından tarafından tüketilebilen nesne oluşturmak için çeşitli yollar gösterir.

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

[Üst]

Örnek: C++ Windows Çalışma Zamanı Bileşeni Oluşturma ve C#'tan Tüketme

Kullanıcı Arabirimi tanımlamak için XAML ve C# kullanan ve yoğun işlemleri gerçekleştirmek için C++ Windows Çalışma Zamanı bileşeni kullanan bir uygulama düşünün. Bu örnekte, C++ bileşeni belirli bir aralıktaki hangi sayıların asal sayı olduklarını hesaplar. Dört Windows Çalışma Zamanı asenkron görev arabirimleri arasındaki farkları göstermek için Visual Studio'da bir Boş Çözüm oluşturun ve onu Primes diye adlandırarak başlayın. Sonra çözüme Windows Çalışma Zamanı Bileşeni projesi ekleyin ve ardından PrimesLibrary diye adlandırın. Oluşturulan C++ başlık dosyasına aşağıdaki kodu ekleyin (Bu örnek adını Class1.h'den Primes.h'e değiştirir). Her public metot dört asenkron arabirimlerden birini tanımlar. Bir değer döndüren metotlar bir Windows::Foundation::Collections::IVector<int> nesnesi döndürür. İlerleme durumunu raporlayan metotlar tamamlanmış genel çalışma yüzdesini tanımlayan double değerler üretir.

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

Not

Genel kural olarak, asenkron yöntem adları Windows Çalışma Zamanı genellikle, "Async" ile biter.

Oluşturulan C++ kaynak dosyasına aşağıdaki kodu ekleyin (Bu örnek adını Class1.cpp'den Primes.cpp'ye değiştirir). is_prime İşlevi kendi giriş asal olup olmadığını belirler. Geri kalan metotlar Primes sınıfını uygular. create_async öğesine yapılan her çağrı, onu çağıran yöntem ile uyumlu olduğunu gösteren bir imza kullanır. Örneğin, çünkü Primes::ComputePrimesAsync öğesi IAsyncAction döndürür, create_async sağlayan iş fonksiyonu bir değer döndürmez ve bir progress_reporter parametre olarak 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 metot ilk olarak giriş parametrelerinin negatif olmadığından emin olmak için doğrulama gerçekleştirir. Eğer bir girdi değeri negatifse metot Platform::InvalidArgumentException fırlatır. Hata yakalama daha sonra bu bölümde açıklanacaktır.

Bu metotları bir Windows Mağazası uygulamasından tüketmek için, Visual Studio çözümüne için ikinci bir proje eklemek için Visual C# Boş Uygulama (XAML) şablonunu kullanın. Bu örnek projeyi Primes diye adlandırır. Sonra, Primes projesinden, PrimesLibrary projesine bir referans/başvuru ekleyin.

Aşağıdaki kodu MainPage.xaml içine ekleyin. Bu kod kullanıcı arabirimini tanımlar, böylece C++ bileşenini çağırabilir ve sonuçlarını görüntüleyebilirsiniz.

<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>

Aşağıdaki kodu MainPage MainPage.xaml sınıfı içine ekleyin. Bu kod bir Primes nesnesi ve düğme olay işleyicileri 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 metotlar, asenkron işlemler tamamlandıktan sonra kullanıcı arabirimini güncelleştirmek için async ve await anahtar sözcüklerini kullanırlar. C# ve Visual Basic için kullanılabilir asenkron modeller hakkında daha fazla bilgi için bkz: C# ile Windows Mağazası Uygulaması için Asenkron Modeller ve VB ile Windows Mağazası Uygulaması için Asenkron Modeller.

getPrimesCancellation ve cancelGetPrimes metotlar kullanıcıya işlemi iptal edebilme yeteneği sağlamak için birlikte çalışırlar. Kullanıcı İptal düğmesini seçtiği zaman, cancelGetPrimes metodu işlemi iptal etmek için IAsyncOperationWithProgress<TResult, TProgress>::İptal çağırır. Temel asenkron işlem yöneten, Eşzamanlılık Çalışma Zamanı, iptal işleminin tamamlandığıyla iletişime geçmek için Windows Çalışma Zamanı tarafından yakalanan bir iç özel durum türü fırlatır. İptal etme modeli hakkında daha fazla bilgi için bkz. ppl iptali.

Önemli

Eşzamanlılık Çalışma Zamanı'nın işlemi iptal ettiğini Windows Çalışma Zamanı öğesine doğru raporlamasını etkinleştirmek için bu iç olağandışı durum türünü yakalamayın.Yani bu şu anlama geliyor, bütün durumları ayrıca yakalamamanız iyi olur (catch (...)).Eğer tüm özel/olağandışı durumları yakalamanız gerekliyse, Windows Çalışma Zamanı öğesinin iptal işlemini tamamlayabildiğinden emin olmak için özel durumu tekrar fırlatın.

Aşağıdaki gösterim her seçenek seçildikten sonra Primes uygulamasını gösterir.

Windows Store app Primes

Diğer diller tarafından tüketilen asenkron görevler oluşturmak için create_async kullanan örnekler için bkz: C++ kullanarak Bing haritalarında Gezi Optimizasyon Örneği ve PPL ile C++'ta Windows 8 Asenkron İşlemler.

[Üst]

Yürütme İş Parçacığını Denetleme

Windows Çalışma Zamanı COM iş parçacığı modelini kullanır. Bu modelde, nesneler senkronizasyonlarını nasıl yakaladıklarına bağlı olarak farklı gruplarda barındırılırlar. İş parçacığı açısından güvenli nesneler çoklu iş parçacıklı grupta (MTA) barındırılır. Tek bir iş parçacığı tarafından erişilen nesneler bir tek iş parçacıklı grupta (STA) barındırılır.

Bir kullanıcı arabirimi olan bir uygulamada ASTA (Application STA) iş parçacığı pencere iletilerini pompalamaktan sorumludur ve yalnızca işlemin içindeki iş parçacığı STA barındırılan UI denetimleri güncelleştirebilir. Bunun iki sonucu vardır. İlk olarak, uygulamayı cevap verebilir kalmasını sağlamak için tüm CPU yoğunluğu ve I/O işlemleri ASTA iş parçacığında çalıştırılmamalıdır. İkinci olarak, arka plan iş parçacığı tarafından gelen sonuçlar UI güncellemek için ASTA'ya geri konması gerekir. Bir C++ Windows Mağazası uygulamasında, MainPage ve tüm diğer XAML sayfaları ATSA üzerinde çalışır. Bu nedenle, ASTA üzerinde tanımlanmış görev devamlılıkları varsayılan olarak orada çalışırlar yani denetimleri devamlılık gövdesinden doğrudan güncelleştirebilirsiniz Ancak, bir görevi başka bir görev içinde iç içe alırsanız, iç içe geçmiş bu görevde herhangi bir devamlılık MTA içinde çalışır. Bu nedenle, bu devamlılıkların hangi içerik üzerinde çalıştırıldığını açıkça belirtmeyi dikkate almanız gerekir.

Bir asenkron işlemden IAsyncOperation<TResult> gibi oluşturulan bir görev, iş parçacığı ayrıntıları yoksaymaya yardımcı olabilecek özel bir mantık kullanır. Bir işlem bir arka plan iş parçacığı üzerinde çalışabilir olmasına rağmen (veya bir iş parçacığı tarafından hiç yedeklenmemiş olabilir), onun devamlılıkları devamlılık işlemlerine başlayan grup üzerinde çalışması varsayılan olarak garanti edilir (diğer bir deyişle, task::then olarak adlandırılan gruptan). Bir devamlılığın yürütme içeriğini denetlemek için concurrency::task_continuation_context sınıfını kullanabilirsiniz. Bu statik yardımcı yöntemleri oluşturmak için task_continuation_context nesnelerini kullanın:

Devamlılığın yürütme içeriğini açıkça kontrol etmek için bir task_continuation_context nesnesini task::then öğesine geçirebilirsiniz ya da yürütme içeriğini açıkça kontrol etmek için görevi başka bir gruba geçirebilir ve sonra task::then çağırabilirsiniz.

Önemli

Çünkü Windows Mağazası uygulamalarının ana kullanıcı arabirimi iş parçacığı STA altında çalışır, STA üzerinde oluşturduğunuz devamlılık varsayılan olarak STA üzerinde çalışır.Buna göre MTA üzerinde oluşturduğunuz devamlılık MTA üzerinde çalışır.

Aşağıdaki bölüm, diskten bir dosyayı okuyan, dosyada bulunan en sık kullanılan sözcükleri bulan ve sonra kullanıcı arabiriminde sonuçlarını gösteren bir uygulamayı gösterir. Son işlem, kullanıcı arabirimini güncelleştirme kullanıcı arabirimi/UI iş parçacığında oluşur.

Önemli

Bu davranış Windows Mağazası uygulamalarına özgüdür.Masaüstü uygulamalar için devamlılığın nerede çalıştığını kontrol etmezsiniz.Bunun yerine, zamanlayıcı devamlılığı çalıştırılacağı bir işçi iş parçacığı seçer.

Önemli

Bir devamlılık gövdesi içindeki STA üzerinde çalışan concurrency::task::wait çağırmayın.Aksi takdirde çalışma zamanı concurrency::invalid_operation fırlatır, çünkü bu yöntem, geçerli iş parçacığını engeller ve uygulamanın yanıt veremez duruma gelmesine neden olabilir.Ancak, görev tabanlı devamlılık içinde öncül görevin sonucunu almak için concurrency::task::get metodunu çağırabilirsiniz.

[Üst]

Örnek: C++ ve XAML ile bir Windows Mağazası Uygulaması içinde Yürütme Denetleme

Bir dosyayı diskten okuyan, dosyada bulunan en sık kullanılan sözcükleri bulan ve sonra kullanıcı arabiriminde sonuçlarını gösteren bir C++ XAML uygulaması düşünün. Bu uygulamayı oluşturmak için Visual Studio'da bir Windows Mağazası Boş Uygulama (XAML) projesi oluşturarak başlayın ve CommonWords diye adlandırın. Uygulama bildiriminizde, uygulamanızı Belgeler klasörüne erişebilirliğini etkinleştirmek için Belgeler Kitaplığı yeteneğini belirtin. Ayrıca metin (.txt) dosya türünü uygulama bildiriminin bildiriler bölümüne ekleyin. Uygulama özellikleri ve bildirimleri hakkında daha fazla bilgi için bkz: Uygulama paketleri ve dağıtım.

MainPage.xaml içindeki Grid öğesini bir ProgressRing öğesi ve bir TextBlock öğesi eklemek için güncelleştirin. ProgressRing işlem sürüyor olduğunu 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 ifadelerini pch.h içine ekleyin.

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

Aşağıdaki yöntem bildirimlerini MainPage (MainPage.h) sınıfına 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 ifadelerini MainPage.cpp içine ekleyin.

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

MainPage.cpp içine MainPage::MakeWordList, MainPage::FindCommonWords, ve MainPage::ShowResults yöntemlerini uygulayın/implemente edin. MainPage::MakeWordList ve MainPage::FindCommonWords hesaplama açısından yoğun işlemleri gerçekleştirir. MainPage::ShowResults yöntemi, kullanıcı arabiriminde hesaplamanın sonucu 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());
}

MainPage oluşturucusunu, Homer tarafından yazılmış Iliad kitabındaki sık kullanılan sözcükleri kullanıcı arabiriminde görüntülemek için devamlılık görevlerinin bir zincirini oluşturmak için düzenleyin. Metni kişisel sözcükler ve sık kullanılan sözcükler diye ikiye bölen ilk iki devamlılık görevi zaman alan bir öğe olabilir ve bu nedenle açıkça arka planda çalışacak biçimde ayarlayın. Kullanıcı Arabirimini güncelleştiren son devamlılık görevi, devamlılık içeriği belirtmez ve bu nedenle grup iş parçacığı 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.
    });
}

Not

Bu örnek, nasıl yürütme bağlamı belirteceğinizi ve bir devamlılığın zincirini nasıl oluşturacağınızı gösterir.Varsayılan olarak asenkron bir işlemden oluşturulan bir görevin onun devamlılığının grubu üzerinde çalıştığını anımsayın task::then.Bu nedenle, bu örnek, kullanıcı arabiriminin bir arka plan iş parçacığı üzerinde gerçekleşmesi gerektiğini kapsamayan bu işlemleri belirtmek için task_continuation_context::use_arbitrary kullanır.

Aşağıdaki gösterim CommonWords uygulamasının sonuçlarını gösterir.

Windows CommonWords app Store

Bu örnekte, iptal etme işlemi desteklenebilirdir çünkü task nesnelerini, create_async destekleyenler, örtülü bir iptal etme belirteci kullanırlar. Eğer görevleriniz bir iş birliği tarzında iptal etme işlemine cevap verme ihtiyacı duyuyorsa, iş fonksiyonunuzu bir cancellation_token nesnesi almak için tanımlayın. PPL içinde iptal etme hakkında daha fazla bilgi için bkz.ppl iptali

[Üst]

Ayrıca bkz.

Kavramlar

Eşzamanlılık çalışma zamanı