Границы контекстов объектов

83

Домены приложений представляют собой логические разделы внутри процесса, которые используются для обслуживания сборок .NET. Однако на этом дело не заканчивается, поскольку каждый домен приложения может быть дополнительно разделен на многочисленные контексты. Контекст в .NET предоставляет возможность закреплять за конкретным объектом "определенное место" в одном домене приложения.

Следует отметить, что если понимание концепции процессов и доменов приложений является довольно важным, то необходимость работы с контекстами объектов в большинстве приложений .NET возникает очень редко.

Используя контекст, CLR-среда обеспечивает надлежащую и согласованную обработку объектов, которые предъявляют специальные требования к этапу выполнения. Она перехватывает вызовы методов, производимых внутри и за пределами конкретного контекста. Этот уровень перехвата позволяет CLR-среде подстраивать текущий вызов метода так, чтобы он соответствовал контекстным настройкам конкретного объекта. Например, в случае определения на C# класса, требующего автоматического обеспечения безопасности в отношении потоков (за счет использования атрибута [Synchronization]). CLR-среда будет создавать во время его размещения так называемый "синхронизированный контекст".

Точно так же, как для каждого процесса создается свой используемый по умолчанию домен приложения, для каждого домена приложения создается применяемый по умолчанию контекст. Этот контекст (иногда еще называемый нулевым из-за того, что он всегда создается в любом домене приложения первым) применяется для группирования вместе объектов .NET, которые не обладают никакими специфическими или уникальными контекстными потребностями.

Процессы, домены приложений и контексты

Как не трудно догадаться, подавляющее большинство объектов .NET загружается именно в нулевой контекст. В случае если CLR-среда определяет, что у создаваемого нового объекта имеются специальные потребности, она создает внутри отвечающего за его обслуживание домена приложения новые границы контекста.

Объекты .NET, которые не требуют никакого особого контекстного сопровождения, называются контекстно-свободными (context-agile). К таким объектам доступ может быть получен из любого места внутри обслуживающего домена приложения без нарушения их требований времени выполнения. Создание контекстно-свободных объектов не требует приложения никаких особых усилий, поскольку при этом вообще ничего не нужно делать (ни снабжать их какими-то контекстными атрибутами, ни наследовать от базового класса System.ContextBoundObject):

// Контекстно-свободный объект загружается в нулевой контекст.
class MyClass { ...

С другой стороны, объекты, которые действительно требуют выделения отдельного контекста, называются контекстно-зависимыми (context-bound). Они должны обязательно наследоваться от базового класса System.ContextBoundObject. Этот базовый класс отражает тот факт, что интересующий объект может функционировать надлежащим образом только в рамках контекста, в котором он был создан. Из-за роли контекста в .NET должно стать совершенно понятно, что в случае попадания контекстно-зависимого объекта каким-то образом в несоответствующий контекст, обязательно произойдет что-то плохое, причем в самый неподходящий момент.

Помимо наследования от System.ContextBoundObject, контекстно-зависимые объекты должны обязательно сопровождаться специальными атрибутами .NET, которые называются контекстными атрибутами. Все контекстные атрибуты наследуются от базового класса ContextAttribute. Теперь давайте рассмотрим конкретный пример.

Предположим, что требуется определить класс (MyClassTS), который автоматически обеспечивает безопасность в отношении потоков, даже без помещения внутрь реализации его членов жестко закодированной логики синхронизации потоков. Чтобы получить такой класс, необходимо просто унаследовать его от ContextBoundObject и применить к нему атрибут [Synchronization], как показано ниже:

using System.Runtime.Remoting.Contexts;
// Этот контекстно-зависимый тип будет загружаться только в синхронизированный (т.е. безопасный к потокам) контекст
[Synchronization]
public class MyClassTS : ContextBoundObject
{ }

Типы, которые сопровождаются атрибутом [Synchronization], всегда загружаются в безопасный к потокам контекст. Зная о специальных контекстных потребностях класса MyThreadSafeObject, теперь представим, какие проблемы будут возникать в случае перемещения соответствующего объекта из синхронизированного контекста в не синхронизированный. Объект сразу же перестанет быть безопасным к потокам и, следовательно, станет кандидатом на массовое повреждение данных, поскольку доступ к нему будут пытаться получить одновременно множество потоков. Наследование MyClassTS от ContextBoundObject дает гарантию, что CLR-среда никогда не будет пытаться перемещать объекты MyClassTS за пределы синхронизированного контекста.

Пройди тесты
Лучший чат для C# программистов