Dela via


Trådning och marskalkning (C++/CX)

I de allra flesta fall kan instanser av Windows Runtime-klasser, till exempel C++-standardobjekt, nås från valfri tråd. Sådana klasser kallas "agile". Ett litet antal Windows Runtime-klasser som levereras med Windows är dock inte agila och måste användas mer som COM-objekt än C++-standardobjekt. Du behöver inte vara EN COM-expert för att använda icke-agila klasser, men du måste ta hänsyn till klassens trådningsmodell och dess hanteringsbeteende. Den här artikeln innehåller bakgrund och vägledning för de sällsynta scenarier där du behöver använda en instans av en icke-agil klass.

Trådningsmodell och marskalkeringsbeteende

En Windows Runtime-klass kan ha stöd för samtidig trådåtkomst på olika sätt, vilket anges av två attribut som tillämpas på den:

  • ThreadingModel attributet kan ha något av värdena – STA, MTA eller Båda, enligt ThreadingModel uppräkningen.

  • MarshallingBehavior attributet kan ha något av värdena – Agile, None eller Standard enligt MarshallingType uppräkningen.

Attributet ThreadingModel anger var klassen läses in när den aktiveras: endast i en sta-kontext (user-interface thread), endast i en bakgrundstrådskontext (MTA) eller i kontexten för tråden som skapar objektet (båda). Attributvärdena MarshallingBehavior refererar till hur objektet beter sig i de olika trådkontexterna. I de flesta fall behöver du inte förstå dessa värden i detalj. Av de klasser som tillhandahålls av Windows-API:et har ThreadingModelcirka 90 procent =Både och MarshallingType=Agile. Det innebär att de kan hantera gängningsinformation på låg nivå transparent och effektivt. När du använder ref new för att skapa en "agil" klass kan du anropa metoder för den från huvudapptråden eller från en eller flera arbetstrådar. Med andra ord kan du använda en agil klass – oavsett om den tillhandahålls av Windows eller av en tredje part – var som helst i koden. Du behöver inte bry dig om klassens trådningsmodell eller marskalkningsbeteende.

Använda Windows Runtime-komponenter

När du skapar en Universell Windows-plattformsapp kan du interagera med både flexibla och icke-agila komponenter. När du interagerar med icke-agila komponenter kan du stöta på följande varning.

Kompilatorvarning C4451 vid användning av icke-agila klasser

Av olika skäl kan vissa klasser inte vara flexibla. Om du kommer åt instanser av icke-agila klasser från både en tråd i användargränssnittet och en bakgrundstråd bör du vara extra noga med att säkerställa korrekt beteende vid körning. Microsoft C++-kompilatorn utfärdar varningar när du instansierar en icke-agil körningsklass i din app i globalt omfång eller deklarerar en icke-agil typ som klassmedlem i en referensklass som i sig är markerad som agil.

Av de icke-agila klasserna är de enklaste att hantera de som har ThreadingModel=Både och MarshallingType=Standard. Du kan göra dessa klasser flexibla bara med hjälp av hjälpklassen Agile<T> . I följande exempel visas en deklaration av ett icke-agilt objekt av typen Windows::Security::Credentials::UI::CredentialPickerOptions^, och kompilatorvarningen som utfärdas som ett resultat.

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

Här är varningen som utfärdas:

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

När du lägger till en referens – i medlemsomfång eller globalt omfång – till ett objekt som har ett marskalkningsbeteende av "Standard" utfärdar kompilatorn en varning som råder dig att omsluta typen i Platform::Agile<T>: Consider using 'Platform::Agile<Windows::Security::Credentials::UI::CredentialPickerOptions>' instead Om du använder Agile<T>kan du använda klassen på samma sätt som vilken annan agil klass som helst. Använd Platform::Agile<T> under dessa omständigheter:

  • Den icke-agila variabeln deklareras i globalt omfång.

  • Den icke-agila variabeln deklareras i klassomfånget och det finns en risk att förbrukning av kod kan smuggla pekaren , det vill vill s.v.s. använda den i en annan lägenhet utan korrekt marskalkering.

Om inget av dessa villkor gäller kan du markera den innehållande klassen som icke-agil. Med andra ord bör du endast lagra icke-agila objekt direkt i icke-agila klasser och hålla icke-agila objekt via Plattform::Agile<T> i agila klasser.

I följande exempel visas hur du använder Agile<T> så att du på ett säkert sätt kan ignorera varningen.

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

    };

Observera att det inte går att Agile skicka som ett returvärde eller en parameter i en referensklass. Metoden Agile<T>::Get() returnerar ett referens-till-objekt (^) som du kan skicka över programmets binära gränssnitt (ABI) i en offentlig metod eller egenskap.

När du skapar en referens till en In-proc Windows Runtime-klass som har ett hanteringsbeteende av "None" utfärdar kompilatorn varning C4451 men föreslår inte att du överväger att använda Platform::Agile<T>. Kompilatorn kan inte erbjuda någon hjälp utöver den här varningen, så det är ditt ansvar att använda klassen korrekt och se till att koden endast anropar STA-komponenter från användargränssnittstråden och MTA-komponenter endast från en bakgrundstråd.

Redigera agila Windows Runtime-komponenter

När du definierar en referensklass i C++/CX är den agil som standard, dvs. den har ThreadingModel=Både och MarshallingType=Agile. Om du använder Windows Runtime C++-mallbiblioteket kan du göra klassen flexibel genom att härleda från FtmBase, som använder FreeThreadedMarshaller. Om du skapar en klass som har ThreadingModel=Båda eller ThreadingModel=MTA kontrollerar du att klassen är trådsäker.

Du kan ändra trådningsmodellen och marskalkeringsbeteendet för en referensklass. Men om du gör ändringar som gör klassen icke-flexibel måste du förstå de konsekvenser som är associerade med dessa ändringar.

I följande exempel visas hur du tillämpar MarshalingBehavior och ThreadingModel attribut på en körningsklass i ett Windows Runtime-klassbibliotek. När en app använder DLL och använder nyckelordet ref new för att aktivera ett MySTAClass klassobjekt aktiveras objektet i en entrådad lägenhet och stöder inte marskalkering.

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

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

En oförseglade klass måste ha inställningar för marskalkerings- och trådattribut så att kompilatorn kan kontrollera att härledda klasser har samma värde för dessa attribut. Om klassen inte uttryckligen har angett inställningarna genererar kompilatorn ett fel och kan inte kompileras. Alla klasser som härleds från en oförseglade klass genererar ett kompilatorfel i något av följande fall:

  • Attributen ThreadingModel och MarshallingBehavior definieras inte i den härledda klassen.

  • Värdena för attributen ThreadingModel och MarshallingBehavior i den härledda klassen matchar inte värdena i basklassen.

Den trådnings- och marskalkeringsinformation som krävs av en Windows Runtime-komponent från tredje part anges i registreringsinformationen för appmanifestet för komponenten. Vi rekommenderar att du gör alla dina Windows Runtime-komponenter flexibla. Detta säkerställer att klientkoden kan anropa komponenten från valfri tråd i appen och förbättrar prestandan för dessa anrop eftersom de är direktanrop som inte har någon marshaling. Om du skriver klassen på det här sättet behöver klientkoden inte använda för att använda Platform::Agile<T> klassen.

Se även

ThreadingModel
MarshallingBehavior