Wątkowość i marshaling (C++/CX)
W przeważającej większości przypadków wystąpienia klas środowisko wykonawcze systemu Windows, takich jak standardowe obiekty języka C++, mogą być dostępne z dowolnego wątku. Takie klasy są określane jako "agile". Jednak niewielka liczba klas środowisko wykonawcze systemu Windows, które są dostarczane z systemem Windows, są niezwinne i muszą być używane bardziej jak obiekty COM niż standardowe obiekty C++. Nie musisz być ekspertem COM, aby korzystać z klas niezwinnych, ale należy wziąć pod uwagę model wątków klasy i jego zachowanie marshalingu. Ten artykuł zawiera podstawowe informacje i wskazówki dotyczące tych rzadkich scenariuszy, w których należy użyć wystąpienia klasy niezwinnej.
Model wątkowy i zachowanie marshalingu
Klasa środowisko wykonawcze systemu Windows może obsługiwać współbieżny dostęp do wątków na różne sposoby, co wskazuje na dwa atrybuty, które są do niego stosowane:
ThreadingModel
Atrybut może mieć jedną z wartości — STA, MTA lub Oba, zgodnie z definicją wyliczeniaThreadingModel
.MarshallingBehavior
Atrybut może mieć jedną z wartości — Agile, None lub Standard zgodnie z definicją wyliczeniaMarshallingType
.
Atrybut ThreadingModel
określa, gdzie klasa jest ładowana po aktywowaniu: tylko w kontekście wątku interfejsu użytkownika (STA), tylko w kontekście wątku tła (MTA) lub w kontekście wątku, który tworzy obiekt (Oba). Wartości MarshallingBehavior
atrybutów odnoszą się do tego, jak obiekt zachowuje się w różnych kontekstach wątków. W większości przypadków nie trzeba szczegółowo rozumieć tych wartości. Spośród klas udostępnianych przez interfejs API systemu Windows około 90 procent ma ThreadingModel
=Zarówno, jak i MarshallingType
=Agile. Oznacza to, że mogą obsługiwać szczegóły wątków niskiego poziomu w sposób niewidoczny i wydajny. Gdy używasz ref new
metody do utworzenia klasy "agile", możesz wywołać metody z głównego wątku aplikacji lub z co najmniej jednego wątku roboczego. Innymi słowy, możesz użyć klasy agile — niezależnie od tego, czy jest ona dostarczana przez system Windows, czy przez inną firmę — z dowolnego miejsca w kodzie. Nie musisz zajmować się modelem wątkowym klasy ani zachowaniem marshalingu.
Korzystanie ze składników środowisko wykonawcze systemu Windows
Podczas tworzenia aplikacji platforma uniwersalna systemu Windows możesz korzystać zarówno ze składników agile, jak i niezwinnych. W przypadku interakcji ze składnikami niezwinnymi może wystąpić następujące ostrzeżenie.
Ostrzeżenie kompilatora C4451 podczas korzystania z klas niezwinnych
Z różnych powodów niektóre klasy nie mogą być zwinne. Jeśli uzyskujesz dostęp do wystąpień klas niezwinnych zarówno z wątku interfejsu użytkownika, jak i wątku w tle, należy zachować szczególną ostrożność, aby zapewnić prawidłowe zachowanie w czasie wykonywania. Kompilator Microsoft C++ zgłasza ostrzeżenia podczas tworzenia wystąpienia klasy niezwinnej w czasie wykonywania w aplikacji w zakresie globalnym lub deklarowania typu niezwinnego jako elementu członkowskiego klasy w klasie ref, która jest oznaczona jako zwinna.
Z klas niezwinnych najłatwiej radzić sobie z tymi, które mają ThreadingModel
=Zarówno, jak i MarshallingType
=Standard. Te klasy można zwinić tylko za pomocą klasy pomocniczej Agile<T>
. W poniższym przykładzie pokazano deklarację obiektu typu Windows::Security::Credentials::UI::CredentialPickerOptions^
non-agile i ostrzeżenie kompilatora, które jest wystawiane w wyniku.
ref class MyOptions
{
public:
property Windows::Security::Credentials::UI::CredentialPickerOptions^ Options
{
Windows::Security::Credentials::UI::CredentialPickerOptions^ get()
{
return _myOptions;
}
}
private:
Windows::Security::Credentials::UI::CredentialPickerOptions^ _myOptions;
};
Oto ostrzeżenie, które zostało wydane:
Warning 1 warning C4451: 'Platform::Agile<T>::_object' : Usage of ref class 'Windows::Security::Credentials::UI::CredentialPickerOptions' inside this context can lead to invalid marshaling of object across contexts. Consider using 'Platform::Agile<Windows::Security::Credentials::UI::CredentialPickerOptions>' instead
Podczas dodawania odwołania — w zakresie składowym lub zakresie globalnym — do obiektu, który ma zachowanie marshalingowe "Standard", kompilator wydaje ostrzeżenie, które zaleca zawijanie typu w Platform::Agile<T>
elemencie : Consider using 'Platform::Agile<Windows::Security::Credentials::UI::CredentialPickerOptions>' instead
Jeśli używasz Agile<T>
metody , możesz użyć klasy, takiej jak dowolna inna klasa agile. Użyj Platform::Agile<T>
w następujących okolicznościach:
Zmienna niezwinna jest deklarowana w zakresie globalnym.
Zmienna niezwinna jest deklarowana w zakresie klasy i istnieje prawdopodobieństwo, że użycie kodu może przemycić wskaźnik — czyli użycie go w innym mieszkaniu bez poprawnego marshalingu.
Jeśli żaden z tych warunków nie ma zastosowania, możesz oznaczyć klasę zawierającą jako niezwinną. Innymi słowy, należy bezpośrednio przechowywać obiekty niezwinne tylko w klasach niezwinnych i przechowywać obiekty niezwinne za pomocą metody Platform::Agile<T> w klasach agile.
W poniższym przykładzie pokazano, jak używać Agile<T>
polecenia , aby można było bezpiecznie zignorować ostrzeżenie.
#include <agile.h>
ref class MyOptions
{
public:
property Windows::Security::Credentials::UI::CredentialPickerOptions^ Options
{
Windows::Security::Credentials::UI::CredentialPickerOptions^ get()
{
return m_myOptions.Get();
}
}
private:
Platform::Agile<Windows::Security::Credentials::UI::CredentialPickerOptions^> m_myOptions;
};
Zwróć uwagę, że Agile
nie można przekazać jako wartości zwracanej ani parametru w klasie ref. Metoda Agile<T>::Get()
zwraca metodę handle-to-object (^), którą można przekazać przez interfejs binarny aplikacji (ABI) w publicznej metodzie lub właściwości.
Podczas tworzenia odwołania do klasy środowisko wykonawcze systemu Windows in-proc, która ma zachowanie marshalingowe "None", kompilator wydaje ostrzeżenie C4451, ale nie sugeruje, aby rozważyć użycie polecenia Platform::Agile<T>
. Kompilator nie może zaoferować żadnej pomocy poza tym ostrzeżeniem, dlatego twoim zadaniem jest prawidłowe użycie klasy i upewnienie się, że kod wywołuje składniki STA tylko z wątku interfejsu użytkownika i składników MTA tylko z wątku w tle.
Tworzenie elastycznych składników środowisko wykonawcze systemu Windows
Podczas definiowania klasy ref w języku C++/CX jest ona domyślnie elastyczna — ma ona ThreadingModel
wartość =Zarówno, jak i MarshallingType
=Agile. Jeśli używasz biblioteki szablonów języka środowisko wykonawcze systemu Windows C++, możesz zwinnieć klasę, korzystając z FtmBase
klasy , która używa FreeThreadedMarshaller
klasy . Jeśli tworzysz klasę z ThreadingModel
wartością =Both lub ThreadingModel
=MTA, upewnij się, że klasa jest bezpieczna wątkowo.
Można zmodyfikować model wątków i marshaling zachowanie klasy ref. Jeśli jednak wprowadzisz zmiany, które renderują klasę niezwinną, musisz zrozumieć implikacje, które są skojarzone z tymi zmianami.
W poniższym przykładzie pokazano, jak zastosować MarshalingBehavior
atrybuty i ThreadingModel
do klasy środowiska uruchomieniowego w bibliotece klas środowisko wykonawcze systemu Windows. Gdy aplikacja używa biblioteki DLL i używa ref new
słowa kluczowego MySTAClass
do aktywowania obiektu klasy, obiekt jest aktywowany w jednym wątku i nie obsługuje marshalingu.
using namespace Windows::Foundation::Metadata;
using namespace Platform;
[Threading(ThreadingModel::STA)]
[MarshalingBehavior(MarshalingType::None)]
public ref class MySTAClass
{
};
Niezaziemowana klasa musi mieć ustawienia atrybutów marshalingu i wątkowania, aby kompilator mógł sprawdzić, czy klasy pochodne mają taką samą wartość dla tych atrybutów. Jeśli klasa nie ma jawnie ustawionych ustawień, kompilator generuje błąd i nie można skompilować. Każda klasa pochodząca z niesealedclass generuje błąd kompilatora w jednym z następujących przypadków:
Atrybuty
ThreadingModel
iMarshallingBehavior
nie są zdefiniowane w klasie pochodnej.Wartości atrybutów
ThreadingModel
iMarshallingBehavior
w klasie pochodnej nie są zgodne z wartościami w klasie bazowej.
Informacje wątkowe i marshalingowe wymagane przez składnik środowisko wykonawcze systemu Windows innej firmy są określone w informacjach dotyczących rejestracji manifestu aplikacji dla składnika. Zalecamy zwinność wszystkich składników środowisko wykonawcze systemu Windows. Dzięki temu kod klienta może wywołać składnik z dowolnego wątku w aplikacji i poprawi wydajność tych wywołań, ponieważ są to bezpośrednie wywołania, które nie mają marshalingu. Jeśli w ten sposób utworzysz klasę, kod klienta nie musi używać Platform::Agile<T>
klasy.
Zobacz też
Opinia
https://aka.ms/ContentUserFeedback.
Dostępne już wkrótce: W 2024 r. będziemy stopniowo wycofywać zgłoszenia z serwisu GitHub jako mechanizm przesyłania opinii na temat zawartości i zastępować go nowym systemem opinii. Aby uzyskać więcej informacji, sprawdź:Prześlij i wyświetl opinię dla