Dela via


Migrering av trådhanteringsfunktionalitet

Det här avsnittet beskriver hur du migrerar trådkoden i ett UWP-program (Universal Windows Platform) till Windows App SDK.

Sammanfattning av skillnader i API och/eller funktioner

UWP:s trådningsmodell är en variant av STA-modellen (single-threaded apartment) med namnet Application STA (ASTA), som blockerar återinträde och hjälper till att undvika olika återinträdesbuggar och dödlägen. En ASTA-tråd kallas även för en UI-tråd.

Windows App SDK använder en standardmodell för STA-trådning, som inte ger samma skydd för återaktivering.

Typen CoreDispatcher migrerar till DispatcherQueue. Och metoden CoreDispatcher.RunAsync migreras till DispatcherQueue.TryEnqueue.

C++/WinRT. Om du använder winrt::resume_foreground med CoreDispatcher, bör du migrera till att i stället använda DispatcherQueue.

ASTA och STA-trådningsmodell

Mer information om ASTA-trådningsmodellen finns i blogginlägget Vad är så speciellt med programSTA?.

Eftersom Windows App SDK:s STA-trådningsmodell inte har samma garantier för att förhindra problem med återaktivering, kan det hända att koden inte fungerar som förväntat om UWP-appen antar att ASTA-trådningsmodellen inte fungerar som förväntat.

En sak att se upp för är återaktivering till XAML-kontroller (se exemplet i En Windows App SDK-migrering av UWP Photo Editor-exempelappen (C++/WinRT)). Och för vissa krascher, till exempel åtkomstöverträdelser, är den direkta kraschanropsstacken vanligtvis den rätta stacken att använda. Men om det är ett stuvat undantag krasch – som har undantagskod: 0xc000027b – krävs mer arbete för att få rätt anropsstack.

Undantag som lagras

Undantagskrascher med undantag sparar ett möjligt fel och används senare om ingen del av koden hanterar undantaget. XAML bestämmer ibland att felet är allvarligt omedelbart, i vilket fall den direkta kraschstacken kan vara bra. Men oftare har stacken vuxit upp innan den bestämdes vara dödlig. Mer information om undantag av typen "stowed exceptions" finns i programmet Inside Show avsnitt Stowed Exception C000027B.

För undantagskrascher (om du vill se en inbäddad meddelandepump eller för att se det specifika undantag som XAML-kontrollen kastar) kan du få mer information om kraschen genom att ladda en kraschdump i Windows Debugger (WinDbg) (se Ladda ned felsökningsverktyg för Windows) och sedan använda !pde.dse för att visa de lagrade undantagen.

PDE-felsökningstillägget (för !pde.dse kommandot) är tillgängligt genom att ladda ned PDE*.zip-filen från OneDrive. Placera den lämpliga x64 eller x86 .dll från zip-filen i winext-katalogen för din WinDbg-installation, så kommer !pde.dse att fungera med lagrade undantagskraschdumpar.

Ofta finns det flera undantag, där vissa i slutet har hanterats eller ignorerats. Oftast är det första stuvade undantaget det intressanta. I vissa fall kan det första undantaget vara en återkastning av det andra, så om det andra undantaget visar sig djupare i samma stack som det första kan det andra undantaget vara orsaken till felet. Felkoden som visas med varje stuvat undantag är också värdefull, eftersom det ger HRESULT- associerad med det undantaget.

Ändra Windows.UI.Core.CoreDispatcher till Microsoft.UI.Dispatching.DispatcherQueue

Det här avsnittet gäller om du använder klassen Windows.UI.Core.CoreDispatcher i UWP-appen. Det inkluderar användning av metoder eller egenskaper som tar eller returnerar en CoreDispatcher, till exempel egenskaperna DependencyObject.Dispatcher och CoreWindow.Dispatcher . Du kommer till exempel att anropa DependencyObject.Dispatcher när du hämtar CoreDispatcher- som tillhör en Windows.UI.Xaml.Controls.Page.

// MainPage.xaml.cs in a UWP app
if (this.Dispatcher.HasThreadAccess)
{
    ...
}
// MainPage.xaml.cpp in a UWP app
if (this->Dispatcher().HasThreadAccess())
{
    ...
}

I stället måste du använda klassen Microsoft.UI.Dispatching.DispatcherQueue i din Windows App SDK-app. Och motsvarande metoder eller egenskaper som tar eller returnerar en DispatcherQueue, till exempel egenskaperna DependencyObject.DispatcherQueue och Microsoft.UI.Xaml.Window.DispatcherQueue. Du kommer till exempel att anropa DependencyObject.DispatcherQueue när du hämtar DispatcherQueue som tillhör en Microsoft.UI.Xaml.Controls.Page (de flesta XAML-objekt är DependencyObjects).

// MainPage.xaml.cs in a Windows App SDK app
if (this.DispatcherQueue.HasThreadAccess)
{
    ...
}
// MainPage.xaml.cpp in a Windows App SDK app
#include <winrt/Microsoft.UI.Dispatching.h>
...
if (this->DispatcherQueue().HasThreadAccess())
{
    ...
}

Ändra CoreDispatcher.RunAsync till DispatcherQueue.TryEnqueue

Det här avsnittet gäller om du använder metoden Windows.UI.Core.CoreDispatcher.RunAsync för att schemalägga en aktivitet som ska köras på huvudgränssnittstråden (eller på tråden som är associerad med en viss Windows.UI.Core.CoreDispatcher).

// MainPage.xaml.cs in a UWP app
public void NotifyUser(string strMessage)
{
    if (this.Dispatcher.HasThreadAccess)
    {
        StatusBlock.Text = strMessage;
    }
    else
    {
        var task = this.Dispatcher.RunAsync(
            Windows.UI.Core.CoreDispatcherPriority.Normal,
            () => StatusBlock.Text = strMessage);
    }
}
// MainPage.cpp in a UWP app
void MainPage::NotifyUser(std::wstring strMessage)
{
    if (this->Dispatcher().HasThreadAccess())
    {
        StatusBlock().Text(strMessage);
    }
    else
    {
        auto task = this->Dispatcher().RunAsync(
            Windows::UI::Core::CoreDispatcherPriority::Normal,
            [strMessage, this]()
            {
                StatusBlock().Text(strMessage);
            });
    }
}

I din Windows App SDK-app använder du i stället metoden Microsoft.UI.Dispatching.DispatcherQueue.TryEnqueue). Den lägger till i Microsoft.UI.Dispatching.DispatcherQueue en uppgift som ska köras på den tråd som är associerad med DispatcherQueue.

// MainPage.xaml.cs in a Windows App SDK app
public void NotifyUser(string strMessage)
{
    if (this.DispatcherQueue.HasThreadAccess)
    {
        StatusBlock.Text = strMessage;
    }
    else
    {
        bool isQueued = this.DispatcherQueue.TryEnqueue(
        Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal,
        () => StatusBlock.Text = strMessage);
    }
}
// MainPage.xaml.cpp in a Windows App SDK app
#include <winrt/Microsoft.UI.Dispatching.h>
...
void MainPage::NotifyUser(std::wstring strMessage)
{
    if (this->DispatcherQueue().HasThreadAccess())
    {
        StatusBlock().Text(strMessage);
    }
    else
    {
        bool isQueued = this->DispatcherQueue().TryEnqueue(
            Microsoft::UI::Dispatching::DispatcherQueuePriority::Normal,
            [strMessage, this]()
            {
                StatusBlock().Text(strMessage);
            });
    }
}

Migrera winrt::resume_foreground (C++/WinRT)

Det här avsnittet gäller om du använder funktionen winrt::resume_foreground i en coroutine i din C++/WinRT UWP-app.

I UWP är användningsfallet för winrt::resume_foreground att växla körning till en förgrundstråd (den förgrundstråden är ofta den som är associerad med en Windows.UI.Core.CoreDispatcher). Här är ett exempel på det.

// MainPage.cpp in a UWP app
winrt::fire_and_forget MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
    ...
    co_await winrt::resume_foreground(this->Dispatcher());
    ...
}

I din applikation med Windows App SDK:

Lägg därför först till en referens till NuGet-paketet Microsoft.Windows.ImplementationLibrary .

Lägg sedan till följande inkludera i pch.h i målprojektet.

#include <wil/cppwinrt_helpers.h>

Och följ sedan mönstret som visas nedan.

// MainPage.xaml.cpp in a Windows App SDK app
...
winrt::fire_and_forget MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
    ...
    co_await wil::resume_foreground(this->DispatcherQueue());
    ...
}

Se även