Migração da funcionalidade de threading
Este tópico descreve como migrar o código de threading em um aplicativo de Plataforma Universal do Windows (UWP) para o SDK do Aplicativo Windows.
Resumo das diferenças de API e/ou recursos
O modelo de threading da UWP é uma variação do modelo STA (apartamento de thread único) chamado ASTA (Application STA), que bloqueia a reentrada e ajuda a evitar vários bugs e deadlocks de reentrada. Um thread ASTA também é conhecido como um thread de interface do usuário.
O SDK do Aplicativo Windows usa um modelo de threading STA padrão, que não fornece as mesmas proteções de reentrada.
O tipo CoreDispatcher migra para DispatcherQueue. E o método CoreDispatcher.RunAsync migra para DispatcherQueue.TryEnqueue.
C++/WinRT. Se você estiver usando winrt::resume_foreground com CoreDispatcher, migre-o para usar DispatcherQueue .
Modelo de threading ASTA para STA
Para obter mais detalhes sobre o modelo de threading do ASTA, consulte a postagem no blog O que é tão especial sobre o STA do Aplicativo?.
Como o modelo de threading STA do SDK do Aplicativo Windows não tem as mesmas garantias em relação à prevenção de problemas de reentrância, se o aplicativo UWP assumir o comportamento de não participante do modelo de threading ASTA, o código poderá não se comportar conforme o esperado.
Uma coisa a watch é a reentrância em controles XAML (consulte o exemplo em Uma migração SDK do Aplicativo Windows do aplicativo de exemplo editor de fotos UWP (C++/WinRT)). E para algumas falhas, como violações de acesso, a pilha de chamadas de falha direta geralmente é a pilha certa a ser usada. No entanto, se for uma falha de exceção, que tem o código de exceção: 0xc000027b, mais trabalho será necessário para obter o conjunto de chamadas correto.
Exceções em stowed
Falhas de exceção em stowed salvam um possível erro e isso é usado posteriormente se nenhuma parte do código manipular a exceção. O XAML às vezes decide que o erro é fatal imediatamente, nesse caso, a pilha de falhas direta pode ser boa. Mas, com mais freqüência, a pilha se desenrola antes de ser determinada como fatal. Para obter mais detalhes sobre exceções ocultas, consulte o episódio Inside Show Stowed Exception C000027B.
Para falhas de exceção armazenadas (para ver uma bomba de mensagem aninhada ou para ver a exceção específica do controle XAML sendo gerada), você pode obter mais informações sobre a falha carregando um despejo de memória no Depurador do Windows (WinDbg) (consulte Baixar ferramentas de depuração para Windows) e, em seguida, usar !pde.dse
para despejar as exceções armazenadas.
A extensão do depurador PDE (para o !pde.dse
comando) está disponível baixando o arquivo PDE*.zip do OneDrive. Coloque o appropiate x64 ou x86 .dll
desse arquivo zip no winext
diretório da instalação do WinDbg e, em seguida !pde.dse
, funcionará em despejos de falha de exceção armazenados.
Frequentemente, haverá várias exceções ocultas, com algumas no final que foram tratadas/ignoradas. Mais comumente, a primeira exceção stowed é a interessante. Em alguns casos, a primeira exceção stowed pode ser um relançamento do segundo, portanto, se a segunda exceção stowed aparecer mais profundamente na mesma pilha que a primeira, a segunda exceção poderá ser a origem do erro. O código de erro mostrado com cada exceção stowed também é valioso, pois isso fornece o HRESULT associado a essa exceção.
Alterar Windows.UI.Core.CoreDispatcher para Microsoft.UI.Dispatching.DispatcherQueue
Esta seção se aplica se você estiver usando a classe Windows.UI.Core.CoreDispatcher em seu aplicativo UWP. Isso inclui o uso de quaisquer métodos ou propriedades que usam ou retornam um CoreDispatcher, como as propriedades DependencyObject.Dispatcher e CoreWindow.Dispatcher . Por exemplo, você chamará DependencyObject.Dispatcher ao recuperar o CoreDispatcher pertencente a um 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())
{
...
}
Em vez disso, em seu aplicativo SDK do Aplicativo Windows, você precisará usar a classe Microsoft.UI.Dispatching.DispatcherQueue. E os métodos ou propriedades correspondentes que recebem ou retornam um DispatcherQueue, como as propriedades DependencyObject.DispatcherQueue e Microsoft.UI.Xaml.Window.DispatcherQueue . Por exemplo, você chamará DependencyObject.DispatcherQueue quando recuperar o DispatcherQueue pertencente a um Microsoft.UI.Xaml.Controls.Page (a maioria dos objetos XAML são 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())
{
...
}
Alterar CoreDispatcher.RunAsync para DispatcherQueue.TryEnqueue
Esta seção se aplica se você estiver usando o método Windows.UI.Core.CoreDispatcher.RunAsync para agendar uma tarefa a ser executada no thread de interface do usuário do main (ou no thread associado a um windows.UI.Core.CoreDispatcher específico).
// 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);
});
}
}
Em seu aplicativo SDK do Aplicativo Windows, use o método Microsoft.UI.Dispatching.DispatcherQueue.TryEnqueue). Ele adiciona ao Microsoft.UI.Dispatching.DispatcherQueue uma tarefa que será executada no thread associado ao 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);
});
}
}
Migrar winrt:: winrt::resume_foreground (C++/WinRT)
Esta seção se aplica se você usar a função winrt::resume_foreground em uma corrotina em seu aplicativo UWP C++/WinRT.
Na UWP, o caso de uso para winrt::resume_foreground é alternar a execução para um thread em primeiro plano (esse thread em primeiro plano geralmente é o associado a um Windows.UI.Core.CoreDispatcher). Aqui está um exemplo disso.
// MainPage.cpp in a UWP app
winrt::fire_and_forget MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
...
co_await winrt::resume_foreground(this->Dispatcher());
...
}
Em seu aplicativo SDK do Aplicativo Windows:
- Em vez de winrt::resume_foreground, você precisará usar wil::resume_foreground (das Bibliotecas de Implementação do Windows (WIL)).
- E, em vez de CoreDispatcher, você precisará usar a classe Microsoft.UI.Dispatching.DispatcherQueue , conforme descrito em Alterar Windows.UI.Core.CoreDispatcher para Microsoft.UI.Dispatching.DispatcherQueue.
Portanto, primeiro adicione uma referência ao pacote NuGet Microsoft.Windows.ImplementationLibrary .
Em seguida, adicione a seguinte inclusão ao pch.h
no projeto de destino.
#include <wil/cppwinrt_helpers.h>
Em seguida, siga o padrão mostrado abaixo.
// 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());
...
}
Windows developer
Comentários
https://aka.ms/ContentUserFeedback.
Em breve: Ao longo de 2024, eliminaremos os problemas do GitHub como o mecanismo de comentários para conteúdo e o substituiremos por um novo sistema de comentários. Para obter mais informações, consulteEnviar e exibir comentários de