Подобная практика приведет к катастрофе, если применять ее в случае объектов из МТА
, так как в этом случае неизвестно, какой поток будет выполнять данный вызов метода. Неудобство STA заключается в том, что он позволяет одновременно выполняться только одному вызову метода, независимо от того, сколько объектов принадлежат к данному апартаменту. В случае МТА потоки могут быть распределены динамически на основании текущих запросов, вне зависимости от количества объектов в апартаменте. Для того чтобы создать параллельные серверные процессы с использованием только однопоточных апартаментов, потребуется много апартаментов, и если не соблюдать осторожность, то может возникнуть непомерное количество потоков. Кроме того, уровень параллелизма в основанных на STA обслуживающих процессах не может превышать общее число объектов в процессе. Если процесс сервера содержит только малое число крупномодульных (coarse-grained) объектов, то удастся обойтись малым числом потоков, даже если каждый объект существует в своем отдельном STA .В будущей реализации СОМ будет, возможно, введен третий тип апартамента – апартамент, арендованный потоками (RTA – rentalthreaded apartment
). Подобно МТА, RTA позволяет входить в апартамент более чем одному потоку. Но, в отличие от МТА , когда поток входит в RTA, он вызывает блокировку всего апартамента (apartment-wide lock) (то есть он как бы арендует апартамент), которая запрещает другим потокам одновременно входить в апартамент. Эта блокировка апартамента снимается, когда поток покидает RTA , что позволяет войти следующему потоку. В этом отношении RTA подобен МТА , за исключением того, что все вызовы методов осуществляются последовательно. Это обстоятельство делает RTA значительно удобнее для классов, относительно которых неизвестно, являются ли они потокобезопасными. Хотя все вызовы в STA также осуществляются сериями, объекты на основе RTA отличаются тем, что в них нет привязки потоков; то есть внутри RTA могут выполняться любые потоки, а не только тот исходный поток, который создал апартамент. Эта свобода от привязки к потоку делает объекты на базе RTA более гибкими и эффективными, чем объекты на основе STA, так как любой поток потенциально может сделать вызов объекта, просто войдя в RTA объекта. На момент написания этого текста еще окончательно не определились детали создания апартаментов RTA и входа в них. За подробностями вы можете обратиться к документации по SDK .Когда поток впервые создается операционной системой как результат вызова CreateProcess
или CreateThread, этому новообразованному потоку не сопоставлен ни один апартамент. Перед тем как использовать СОМ, новый поток должен войти в какой-либо апартамент путем вызова одной из приведенных далее API-функций.В Windows NT 5.0 это будет изменено. За подробностями обращайтесь к документации по SDK.
HRESULT CoinitializeEx(void *pvReserved, DWORD dwFlags);
HRESULT Coinitialize(void *pvReserved);
HRESULT OleInitialize(vo1d *pvReserved);
Для всех трех только что описанных API-функций первый параметр зарезервирован и должен равняться нулю.
CoInitializeEx
является API-функцией самого низкого уровня и позволяет вызывающему объекту определять, в какой тип апартамента нужно войти. Для того чтобы войти в МТА всего процесса, вызывающий объект должен использовать флаг COINIT_MULTITHREADED:
HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);
Для входа во вновь соаданный STA
вызывающий объект должен выставить флаг COINIT_APARTMENTTHREADED:
HRESULT hr = CoInitializeEx(0, COINIT_APARTMENTTHREADED);
Каждый поток в процессе, который вызывает CoInitializeEx
с применением COINIT_MULTITHREADED, выполняется в том же самом апартаменте. Каждый поток, который вызывает CoInitiаlizeEx с применением COINIT_APARTMENTTHREADED, выполняется в отдельном апартаменте, в который не могут входить никакие другие потоки. CoInitialize – это традиционная подпрограмма, которая просто вызывает CoInitializeEx с флагом COINIT_APARTMENTTHREADED. Olelnitialize сначала вызывает CoInitialize, а затем инициализирует несколько подсистем из OLE-приложений, таких как OLE Drag and Drop и OLE Clipboard. Если не предполагается использовать эти службы более высокого уровня, то в общем случае предпочтительнее использовать CoInitialize или CoInitializeEx.