Многопоточные квартиры
В многопоточной модели квартиры все потоки в процессе, которые были инициализированы как свободные потоки, находятся в одной квартире. Поэтому маршалировать между потоками не нужно. Потоки не должны извлекать и отправлять сообщения, так как COM не использует сообщения окна в этой модели.
Вызовы методов объектов в многопоточной квартире можно выполнять на любом потоке в квартире. Сериализация вызовов отсутствует; многие вызовы могут возникать в одном методе или в один и тот же объект одновременно. Объекты, созданные в многопоточной квартире, должны в любое время обрабатывать вызовы методов из других потоков.
Так как вызовы объектов не сериализуются каким-либо образом, параллелизм многопоточных объектов обеспечивает максимальную производительность и использует лучшее преимущество многопроцессорного оборудования для межпоточных, кросспроцессорных вызовов и вызовов между машинами. Однако это означает, что код для объектов должен обеспечивать синхронизацию в реализации интерфейса, как правило, с помощью примитивов синхронизации, таких как объекты событий, критически важные разделы, мьютексы или семафоры, описанные далее в этом разделе. Кроме того, поскольку объект не управляет временем существования потоков, к которым он обращается, в объекте не может храниться состояние конкретного потока (в локальном хранилище потока).
Ниже приведены некоторые важные рекомендации по синхронизации для многопоточных квартир:
- COM обеспечивает синхронизацию вызовов только для однопоточных квартир.
- Многопоточные квартиры не получают вызовы при выполнении звонков (в одном потоке).
- Многопоточные квартиры не могут выполнять входные синхронизированные вызовы.
- Асинхронные вызовы преобразуются в синхронные вызовы в многопоточных квартирах.
- Фильтр сообщений не вызывается для любого потока в многопоточной квартире.
Чтобы инициализировать поток как свободный поток, вызовите CoInitializeEx, указав COINIT_MULTITHREADED. Сведения о потоковом потоке внутрипроцессного сервера см. в разделе "Проблемы потоков сервера в процессе".
Несколько клиентов могут одновременно вызывать из разных потоков объект, поддерживающий свободный поток. В бесплатных исходящих серверах COM через подсистему RPC создает пул потоков в процессе сервера и вызов клиента (или несколько клиентских вызовов) в любой из этих потоков в любое время. Сервер вне процесса также должен реализовать синхронизацию в фабрике классов. Объекты без потоков могут получать прямые вызовы из нескольких потоков клиента.
Клиент может выполнять COM-работу в нескольких потоках. Все потоки принадлежат к одной многопоточной квартире. Указатели интерфейса передаются непосредственно из потока в поток в многопоточной квартире, поэтому указатели интерфейса не маршалируются между потоками. Фильтры сообщений (реализации IMessageFilter) не используются в многопоточных квартирах. Поток клиента приостанавливается при выполнении com-вызова к объектам вне квартиры и возобновляется при возвращении вызова. Вызовы между процессами по-прежнему обрабатываются RPC.
Потоки, инициализированные с помощью модели свободного потока, должны реализовать собственную синхронизацию. Как упоминание ранее в этом разделе, Windows включает эту реализацию с помощью следующих примитивов синхронизации:
- Объекты событий позволяют сигнализировать одному или нескольким потокам о том, что произошло событие. Любой поток в процессе может создать объект события. Дескриптор события возвращается функцией создания событий CreateEvent. После создания объекта события потоки с дескриптором объекта могут ждать его до продолжения выполнения.
- Критические разделы используются для раздела кода, требующего эксклюзивного доступа к некоторому набору общих данных, прежде чем его можно будет выполнить, и это используется только потоками в рамках одного процесса. Критически важный раздел похож на тернстиль, через который может пройти только один поток за раз, работая следующим образом:
- Чтобы не более одного потока за раз получать доступ к общим данным, основной поток процесса выделяет глобальную структуру данных CRITICAL_SECTION и инициализирует ее члены. Поток, входящий в критически важный раздел, вызывает функцию EnterCriticalSection и изменяет элементы структуры данных.
- Поток, пытающийся ввести критический раздел, вызывает ВводCriticalSection, который проверка, чтобы узнать, была ли изменена структура данных CRITICAL_SECTION. В этом случае другой поток в настоящее время находится в критическом разделе, а последующий поток помещается в спящий режим. Поток, покидающий критический раздел, вызывает LeaveCriticalSection, который сбрасывает структуру данных. Когда поток покидает критически важный раздел, система просыпается из одного из спящих потоков, который затем входит в критически важный раздел.
- Мьютексы выполняют ту же функцию, что и критически важный раздел, за исключением того, что мьютекс доступен для потоков, выполняемых в различных процессах. Владение объектом мьютекса похоже на пол в дебатах. Процесс создает объект мьютекса, вызывая функцию CreateMutex , которая возвращает дескриптор. Первый поток, запрашивающий объект мьютекса, получает его владение. После завершения работы потока с мьютексом владение передается другим потокам на основе первого начала.
- Семафоры используются для поддержания количества ссылок на некоторый доступный ресурс. Поток создает семафор для ресурса, вызывая функцию CreateSemaphore и передав указатель на ресурс, начальное число ресурсов и максимальное число ресурсов. Эта функция возвращает дескриптор. Поток, запрашивающий ресурс, передает его дескриптор семафора в вызове функции WaitForSingleObject . Объект семафора опрашивает ресурс, чтобы определить, доступен ли он. В этом случае семафор уменьшает количество ресурсов и просыпает поток ожидания. Если число равно нулю, поток остается спящим, пока другой поток не освобождает ресурс, что приводит к тому, что семафор увеличивает число до одного.
См. также