Threading und Marshalling (C++/CX)Threading and Marshaling (C++/CX)

In der Mehrzahl der Fälle können Instanzen von Windows-Runtime-Klassen wie Standard-c++-Objekten, von jedem Thread aus zugegriffen werden.In the vast majority of cases, instances of Windows Runtime classes, like standard C++ objects, can be accessed from any thread. Solche Klassen werden als "agil" bezeichnet.Such classes are referred to as "agile". Eine kleine Anzahl von Windows-Runtime-Klassen, die mit Windows ausgelieferten nicht agil und mehr verarbeitet werden muss, wie COM-Objekte als Standard-c++-Objekten.However, a small number of Windows Runtime classes that ship with Windows are non-agile, and must be consumed more like COM objects than standard C++ objects. Sie müssen zwar kein COM-Experte sein, um nicht agile Klassen zu verwenden, aber das Threadmodell dieser Klassen sowie ihr Marshallingverhalten beachten.You don't need to be a COM expert to use non-agile classes, but you do need to take into consideration the class's threading model and its marshaling behavior. Dieser Artikel ist ein Leitfaden für die seltenen Fälle, in denen Sie die Instanz einer nicht agilen Klasse verarbeiten müssen.This article provides background and guidance for those rare scenarios in which you need to consume an instance of a non-agile class.

Threadmodell und MarshallingverhaltenThreading model and marshaling behavior

Eine Windows-Runtime-Klasse kann gleichzeitigen Threadzugriff auf verschiedene Arten unterstützen, wie durch zwei Attribute angegeben, die darauf angewendet werden:A Windows Runtime class can support concurrent thread access in various ways, as indicated by two attributes that are applied to it:

  • Das AttributThreadingModel kann einen der Werte STA, MTA oder Both besitzen, die durch die Enumeration ThreadingModel definiert werden.ThreadingModel attribute can have one of the values—STA, MTA, or Both, as defined by the ThreadingModel enumeration.

  • Das AttributMarshallingBehavior kann einen der Werte Agile, None oder Standard besitzen, die durch die Enumeration MarshallingType definiert werden.MarshallingBehavior attribute can have one of the values—Agile, None, or Standard as defined by the MarshallingType enumeration.

    Das Attribut ThreadingModel gibt an, wo die Klasse bei der Aktivierung geladen wird: Nur in einem Benutzeroberflächenthread-Kontext (STA), nur in einem Hintergrundthread-Kontext (MTA) oder im Kontext des Threads, der das Objekt erstellt (Both).The ThreadingModel attribute specifies where the class is loaded when activated: only in a user-interface thread (STA) context, only in a background thread (MTA) context, or in the context of the thread that creates the object (Both). Die Werte des MarshallingBehavior -Attributs beziehen sich darauf, wie sich das Objekt im jeweiligen Threadkontext verhält. In den meisten Fällen benötigen Sie keine Kenntnisse über diese Details.The MarshallingBehavior attribute values refer to how the object behaves in the various threading contexts; in most cases, you don’t have to understand these values in detail. Von den Klassen, die von der Windows-API bereitgestellt werden, haben ungefähr 90 Prozent ThreadingModel=Both und MarshallingType=Agile.Of the classes that are provided by the Windows API, about 90 percent have ThreadingModel=Both and MarshallingType=Agile. Das bedeutet, dass sie Threadingdetails auf niedriger Ebene transparent und effizient verarbeiten können.This means that they can handle low-level threading details transparently and efficiently. Wenn Sie ref new verwenden, um eine "agile" Klasse zu erstellen, können Sie Methoden dafür aus dem Haupt-App-Thread oder aus einem oder mehreren Arbeitsthreads aufrufen.When you use ref new to create an "agile" class, you can call methods on it from your main app thread or from one or more worker threads. Das heißt, Sie können von jeder Stelle im Code aus eine agile Klasse verwenden – unabhängig davon, ob sie von Windows oder von einem Drittanbieter bereitgestellt wird.In other words, you can use an agile class—no matter whether it's provided by Windows or by a third party—from anywhere in your code. Sie müssen nicht auf das Threadingmodell oder das Marshallingverhalten der Klasse achten.You don’t have to be concerned with the class’s threading model or marshaling behavior.

Verarbeiten von Windows-Runtime-KomponentenConsuming Windows Runtime components

Wenn Sie eine universelle Windows-Plattform-app erstellen, können Sie mit Agile- und nicht agilen Komponenten interagieren.When you create a Universal Windows Platform app, you might interact with both agile and non-agile components. Wenn Sie mit nicht agilen Komponenten interagieren, wird möglicherweise die folgende Warnung angezeigt.When you interact with non-agile components, you may encounter the following warning.

Compilerwarnung bei der Nutzung von nicht agilen Klassen (C4451)Compiler warning when consuming non-agile classes (C4451)

Aus verschiedenen Gründen können einige Klassen nicht agil sein.For various reasons, some classes can't be agile. Wenn Sie auf Instanzen von nicht agilen Klassen sowohl über einen Benutzeroberflächenthread als auch über einen Hintergrundthread zugreifen, achten Sie besonders darauf, das richtige Verhalten zur Laufzeit sicherzustellen.If you are accessing instances of non-agile classes from both a user-interface thread and a background thread, then take extra care to ensure correct behavior at run time. Der Visual C++-Compiler gibt Warnungen aus, wenn Sie eine nicht agile Laufzeitklasse in der App im globalen Gültigkeitsbereich instanziieren oder einen nicht agilen Typ als Klassenmember in einer Verweisklasse deklarieren, die selbst als agil gekennzeichnet ist.The Visual C++ compiler issues warnings when you instantiate a non-agile run-time class in your app at global scope or declare a non-agile type as a class member in a ref class that itself is marked as agile.

Von den nicht agilen Klassen sind diejenigen am einfachsten zu behandeln, die ThreadingModel=Both und MarshallingType=Standard haben.Of the non-agile classes, the easiest to deal with are those that have ThreadingModel=Both and MarshallingType=Standard. Sie können diese Klassen agil machen, indem Sie einfach die Hilfsklasse Agile<T> verwenden.You can make these classes agile just by using the Agile<T> helper class. Das folgende Beispiel zeigt eine Deklaration eines nicht agilen Objekts des Typs Windows::Security::Credentials::UI::CredentialPickerOptions^und die Compilerwarnung, die infolgedessen ausgegeben wird.The following example shows a declaration of a non-agile object of type Windows::Security::Credentials::UI::CredentialPickerOptions^, and the compiler warning that's issued as a result.


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

Hier ist die Warnung, die ausgegeben wird:Here's the warning that's issued:

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

Wenn Sie im Member- oder im globalen Gültigkeitsbereich zu einem Objekt einen Verweis hinzufügen, der das Marshallingverhalten "Standard" hat, gibt der Compiler eine Warnung aus, die Sie auffordert, den Typ stattdessen in Platform::Agile<T>: Consider using 'Platform::Agile<Windows::Security::Credentials::UI::CredentialPickerOptions>' instead zu umschließen. Wenn Sie Agile<T>verwenden, können Sie die Klasse wie jede andere agile Klasse nutzen.When you add a reference—at member scope or global scope—to an object that has a marshaling behavior of "Standard", the compiler issues a warning that advises you to wrap the type in Platform::Agile<T>: Consider using 'Platform::Agile<Windows::Security::Credentials::UI::CredentialPickerOptions>' instead If you use Agile<T>, you can consume the class like you can any other agile class. Verwenden Sie in diesem Fall Platform::Agile<T> :Use Platform::Agile<T> in these circumstances:

  • Die nicht agile Variable wird im globalen Gültigkeitsbereich deklariert.The non-agile variable is declared at global scope.

  • Die nicht agile Variable wird im Klassengültigkeitsbereich deklariert, und es besteht die Möglichkeit, dass verwendeter Code den Zeiger einschmuggelt, d. h. ihn in einem anderen Apartment ohne das richtige Marshalling verwendet.The non-agile variable is declared at class scope and there is a chance that consuming code might smuggle the pointer—that is, use it in a different apartment without correct marshaling.

    Ist keine dieser Bedingungen zutreffend, können Sie die enthaltende Klasse als nicht agil markieren.If neither of those conditions apply, then you can mark the containing class as non-agile. Das heißt, Sie sollten direkt nicht agile Objekte nur in nicht agilen Klassen halten und nicht agile Objekte über Platform:: Agile<T > in agilen Klassen.In other words, you should directly hold non-agile objects only in non-agile classes, and hold non-agile objects via Platform::Agile<T> in agile classes.

    Im folgenden Beispiel wird gezeigt, wie Sie Agile<T> verwenden müssen, damit Sie die Warnung sicher ignorieren können.The following example shows how to use Agile<T> so that you can safely ignore the warning.


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

    };  

Beachten Sie, dass Agile nicht als Rückgabewert oder Parameter in einer Verweisklasse übergeben werden kann.Notice that Agile cannot be passed as a return value or parameter in a ref class. Die Methode Agile<T>::Get() gibt ein "handle-to-object" (^) zurück, das Sie über die Anwendungsbinärdateischnittstelle (ABI) in einer öffentlichen Methode oder Eigenschaft übergeben können.The Agile<T>::Get() method returns a handle-to-object (^) that you can pass across the application binary interface (ABI) in a public method or property.

In Visual C++, wenn Sie einen Verweis auf eine prozessinterne Windows-Runtime-Klasse erstellen, die ein Marshallingverhalten von "None" hat der Compiler gibt die Warnung c4451 aus, schlägt jedoch nicht vor, dass Sie erwägen, Platform::Agile<T>.In Visual C++, when you create a reference to an in-proc Windows Runtime class that has a marshaling behavior of "None", the compiler issues warning C4451 but doesn't suggest that you consider using Platform::Agile<T>. Der Compiler kann über diese Warnung hinaus keine Hilfe anbieten, sodass es in Ihrer Verantwortung liegt, die Klasse richtig zu verwenden und sicherzustellen, dass der Code STA-Komponenten nur aus dem Benutzeroberflächenthread und MTA-Komponenten nur aus einem Hintergrundthread aufruft.The compiler can't offer any help beyond this warning, so it's your responsibility to use the class correctly and ensure that your code calls STA components only from the user-interface thread, and MTA components only from a background thread.

Erstellen von agile-Windows-Runtime-KomponentenAuthoring agile Windows Runtime components

Beim Definieren einer Verweisklasse in C + c++ / CX, ist sie standardmäßig agil – d. h. er weist ThreadingModel= Both und MarshallingType= Agile.When you define a ref class in C++/CX, it's agile by default—that is, it has ThreadingModel=Both and MarshallingType=Agile. Wenn Sie Windows Runtime C++ Template LibraryWindows Runtime C++ Template Libraryverwenden, können Sie die Klasse agil machen, indem Sie von FtmBaseableiten, das FreeThreadedMarshallerverwendet.If you're using the Windows Runtime C++ Template LibraryWindows Runtime C++ Template Library, you can make your class agile by deriving from FtmBase, which uses the FreeThreadedMarshaller. Wenn Sie eine Klasse erstellen, die ThreadingModel=Both oder ThreadingModel=MTA hat, überprüfen Sie, ob die Klasse threadsicher ist.If you author a class that has ThreadingModel=Both or ThreadingModel=MTA, make sure that the class is thread-safe. Weitere Informationen finden Sie unter Erstellen und Verwenden von Objekten (WRL).For more information, see Create and Consume Objects (WRL).

Sie können das Threadingmodell und das Marshallingverhalten einer Verweisklasse ändern.You can modify the threading model and marshaling behavior of a ref class. Wenn Sie Änderungen vornehmen, die die Klasse zu "nicht agil" rendern, müssen Sie die Auswirkungen verstehen, die mit diesen Änderungen verbunden sind.However, if you make changes that render the class non-agile, you must understand the implications that are associated with those changes.

Im folgende Beispiel wird gezeigt, wie anzuwendende MarshalingBehavior und ThreadingModel Attribute auf eine Laufzeitklasse in einer Windows-Runtime-Klassenbibliothek.The following example shows how to apply MarshalingBehavior and ThreadingModel attributes to a runtime class in a Windows Runtime class library. Wenn eine App die DLL verwendet und das Schlüsselwort ref new benutzt, um ein MySTAClass -Klassenobjekt zu aktivieren, ist das Objekt in einem Singlethread-Apartment aktiviert und unterstützt kein Marshalling.When an app uses the DLL and uses the ref new keyword to activate a MySTAClass class object, the object is activated in a single-threaded apartment and doesn't support marshaling.

using namespace Windows::Foundation::Metadata;  
using namespace Platform;  

[Threading(ThreadingModel::STA)]  
[MarshalingBehavior(MarshalingType::None)]   
public ref class MySTAClass  
{  
};  

In einer unversiegelten Klasse müssen die Marshalling- und Threadingattribute festgelegt sein, damit der Compiler überprüfen kann, ob abgeleitete Klassen für diese Attribute den gleichen Wert haben.An unsealed class must have marshaling and threading attribute settings so that the compiler can verify that derived classes have the same value for these attributes. Wenn die Klasse diese Einstellungen nicht aufweist, generiert der Compiler einen Fehler, und es findet keine Kompilierung statt.If the class doesn't have the settings set explicitly, the compiler generates an error and fails to compile. Jede Klasse, die von einer unversiegelten Klasse abgeleitet ist, generiert in den folgenden Fällen einen Compilerfehler:Any class that's derived from an unsealedclass generates a compiler error in either of these cases:

  • Die Attribute ThreadingModel und MarshallingBehavior sind in der abgeleiteten Klasse nicht definiert.The ThreadingModel and MarshallingBehavior attributes are not defined in the derived class.

  • Die Werte der Attribute ThreadingModel und MarshallingBehavior stimmen in der abgeleiteten Klasse nicht mit denen in der Basisklasse überein.The values of the ThreadingModel and MarshallingBehavior attributes in the derived class don't match those in the base class.

    Die Threading- und Marshallinginformationen, die von einer Drittanbieter-Windows-Runtime-Komponente erforderlich ist, wird in den app-manifestregistrierungsinformationen für die Komponente angegeben.The threading and marshaling information that's required by a third-party Windows Runtime component is specified in the app manifest registration information for the component. Es wird empfohlen, dass Sie alle Windows-Runtime-Komponenten agil.We recommend that you make all of your Windows Runtime components agile. Dadurch wird sichergestellt, dass Clientcode die Komponente von jedem Thread in der App aufrufen kann. Außerdem wird dadurch die Leistung dieser Aufrufe verbessert, da sie direkte Aufrufe sind, die kein Marshalling haben.This ensures that client code can call your component from any thread in the app, and improves the performance of those calls because they are direct calls that have no marshaling. Wenn Sie die Klasse auf diese Weise erstellen, braucht Clientcode Platform::Agile<T> nicht zu verwenden, um die Klasse zu nutzen.If you author your class in this way, then client code doesn't have to use Platform::Agile<T> to consume your class.

Siehe auchSee Also

ThreadingModel ThreadingModel
MarshallingBehaviorMarshallingBehavior