Работа с потоками и маршалинг (C++/CX)

В большинстве случаев доступ к экземплярам классов среда выполнения Windows, таких как стандартные объекты C++, можно получить из любого потока. Такие классы называются "гибкими". Однако небольшое количество классов среда выполнения Windows, которые отправляются с Windows, являются не гибкими, и их необходимо использовать больше, как COM-объекты, чем стандартные объекты C++. Для работы с негибкими классами не нужно быть специалистом по COM, однако нужно учитывать модель потоков классов и их механизмы маршалинга. В этой статье приведены общие сведения и инструкции по реализации редких сценариев, в которых приходится использовать экземпляры негибких классов.

Модель потоков и механизмы маршалинга

Класс среда выполнения Windows может поддерживать одновременный доступ к потокам различными способами, как указано двумя атрибутами, применяемыми к нему:

  • АтрибутThreadingModel может иметь одно из следующих значений: STA, MTA или Both, которые определены в перечислении ThreadingModel .

  • АтрибутMarshallingBehavior может иметь одно из следующих значений: Agile, None или Standard, которые определены в перечислении MarshallingType .

Атрибут ThreadingModel определяет, где загружается класс при активации: только в контексте потока пользовательского интерфейса (STA), только в контексте фонового потока (MTA) или в контексте потока, создающего объект (Both). Значения MarshallingBehavior атрибутов ссылаются на то, как объект ведет себя в различных контекстах потоков. В большинстве случаев вам не нужно подробно понимать эти значения. Среди классов, предоставляемых API Windows, около 90 процентов имеют значения атрибутов ThreadingModel=Both и MarshallingType=Agile. Это означает, что они могут обрабатывать низкоуровневые сведения потоков прозрачно и эффективно. Если создать гибкий класс с помощью ключевого слова ref new , его методы можно из основного потока приложения или из одного или нескольких рабочих потоков. Иначе говоря, гибкий класс можно использовать из любого места в коде, независимо от того, предоставляется ли он Windows или сторонними разработчиками. Вам не нужно беспокоиться о модели потоков класса или поведении маршалинга.

Использование компонентов среда выполнения Windows

При создании приложения универсальная платформа Windows вы можете взаимодействовать как с гибкими, так и не гибкими компонентами. При работе с негибкими компонентами может возникнуть следующее предупреждение.

Предупреждение компилятора C4451 при использовании негибких классов

По различным причинам некоторые классы не могут быть гибкими. Если вы обращаетесь к экземплярам негибких классов и из потока пользовательского интерфейса, и из фонового потока, необходимо уделить особое внимание тому, чтобы обеспечить правильное поведение во время выполнения. Компилятор Microsoft C++ выдает предупреждения при создании экземпляра класса, отличного от гибкой среды выполнения в приложении, в глобальном область или объявлении не гибкого типа как члена класса в классе ссылок, который сам помечается как гибкий.

Из негибких классов проще всего работать с теми, у которых ThreadingModel=Both и MarshallingType=Standard. Эти классы можно сделать гибкими с помощью вспомогательного класса Agile<T> . В следующем примере показано объявление негибкого объекта типа Windows::Security::Credentials::UI::CredentialPickerOptions^и результирующее предупреждение компилятора.

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

Выдается следующее предупреждение:

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

При добавлении ссылки (в области членов или глобальной области) на объект, имеющий поведение маршалинга "Standard", компилятор выдает предупреждение, рекомендующее заключить этот тип в оболочку Platform::Agile<T>: Consider using 'Platform::Agile<Windows::Security::Credentials::UI::CredentialPickerOptions>' instead Если воспользоваться типом Agile<T>, класс можно будет использовать как любой другой гибкий класс. Используйте Platform::Agile<T> в следующих ситуациях:

  • Негибкая переменная объявляется в глобальной области.

  • Негибкая переменная объявляется в области класса, и существует возможность того, что код использует указатель в другом подразделении без надлежащего маршалинга.

Если ни одно из этих условий не выполняется, можно пометить содержащий класс как негибкий. Другими словами, следует напрямую хранить негибкие объекты только в негибких классах, а также хранить негибкие объекты с помощью Platform::<Agile T> в гибких классах.

В следующем примере показано, как благодаря Agile<T> можно пропустить это предупреждение без последствий.

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

    };

Обратите внимание, что Agile нельзя передавать в качестве возвращаемого значения или параметра в классе ссылки. Метод Agile<T>::Get() возвращает дескриптор объекта (^), который можно передать через границу интерфейса ABI в открытом методе или свойстве.

При создании ссылки на класс in-proc среда выполнения Windows с маршалингом "Нет", компилятор выдает предупреждение C4451, но не предлагает использовать его.Platform::Agile<T> Компилятор не может ничем помочь помимо этого предупреждения, поэтому вам необходимо самостоятельно обеспечить надлежащую работу класса и убедиться, что код вызывает компоненты однопотокового подразделения (STA) только из потока пользовательского интерфейса, а компоненты многопотокового подразделения (MTA) — только из фонового потока.

Разработка компонентов гибкой среда выполнения Windows

При определении класса ссылок в C++/CX он по умолчанию является гибким, т. е. имеет ThreadingModelзначение =И MarshallingType=Agile. Если вы используете библиотеку шаблонов C++ среда выполнения Windows, вы можете сделать класс гибким, исходя из FtmBaseкоторого используется FreeThreadedMarshaller. Создавая класс с атрибутами ThreadingModel=Both или ThreadingModel=MTA, убедитесь, что он является потокобезопасным.

Потоковую модель и поведение маршалинга класса ссылки можно изменять. Однако если внести изменения, которые делают класс негибким, необходимо четко понимать их последствия.

В следующем примере показано, как применять MarshalingBehavior и ThreadingModel атрибуты к классу среды выполнения в библиотеке классов среда выполнения Windows. Если приложение использует библиотеку DLL и в нем активируется объект класса ref new с помощью ключевого слова MySTAClass , этот объект активируется в однопотоковом подразделении и не поддерживает маршалинг.

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

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

Незапечатанный класс должен иметь атрибуты маршалинга и потоковой модели, чтобы компилятор мог проверить, что производные классы имеют такие же значения этих атрибутов. Если эти параметры не заданы для класса явным образом, компилятор выдает ошибку и не выполняет компиляцию. Любой класс, производный от незапечатанного класса, выдает ошибку компилятора в каждом из следующих случаев:

  • Атрибуты ThreadingModel и MarshallingBehavior не определены в производном классе.

  • Значения атрибутов ThreadingModel и MarshallingBehavior в производном классе не соответствуют аналогичным атрибутам базового класса.

Потоки и маршалинг сведений, необходимые стороннему компоненту среда выполнения Windows, указываются в сведениях о регистрации манифеста приложения для компонента. Мы рекомендуем сделать все компоненты среда выполнения Windows гибкими. Это гарантирует, что клиентский код сможет вызывать компонент из любого потока приложения, и улучшает производительность таких вызовов, поскольку они являются прямыми вызовами без маршалирования. Если создать класс таким образом, клиентскому коду не придется применять Platform::Agile<T> , чтобы использовать этот класс.

См. также

ThreadingModel
MarshallingBehavior