Сущность технологии СОМ. Библиотека программиста

На нашем литературном портале можно бесплатно читать книгу Сущность технологии СОМ. Библиотека программиста, Бокс Дональд-- . Жанр: Программирование. Онлайн библиотека дает возможность прочитать весь текст и даже без регистрации и СМС подтверждения на нашем литературном портале bazaknig.info.
Сущность технологии СОМ. Библиотека программиста
Название: Сущность технологии СОМ. Библиотека программиста
Дата добавления: 16 январь 2020
Количество просмотров: 278
Читать онлайн

Сущность технологии СОМ. Библиотека программиста читать книгу онлайн

Сущность технологии СОМ. Библиотека программиста - читать бесплатно онлайн , автор Бокс Дональд

В этой книге СОМ исследуется с точки зрения разработчика C++. Написанная ведущим специалистом по модели компонентных объектов СОМ, она раскрывает сущность СОМ, помогая разработчикам правильно понять не только методы модели программирования СОМ, но и ее основу. Понимание мотивов создания СОМ и ее аспектов, касающихся распределенных систем, чрезвычайно важно для тех разработчиков, которые желают пойти дальше простейших приложений СОМ и стать по-настоящему эффективными СОМ-программистами. Показывая, почему СОМ для распределенных систем (Distributed СОМ) работает именно так, а не иначе, Дон Бокс дает вам возможность применять эту модель творчески и эффективно для ежедневных задач программирования.

Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала

1 ... 76 77 78 79 80 81 82 83 84 ... 118 ВПЕРЕД
Перейти на страницу:

if (CoReleaseServerProcess() == 0)

SetEvent(g_heventShutdown);

}

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

Даже при использовании функций CoAddRefServerProcess / CoReleaseServerProcess все еще остаются возможности для гонки. Возможно, что во время выполнения CoReleaseServerProcess на уровне RPC будет получен входящий запрос на активацию от SCM. Если вызов от SCM диспетчеризован после того, как функция CoReleaseServerProcess снимает свою блокировку библиотеки COM, то активационный запрос отметит, что объект класса уже помечен как приостановленный, и в SCM будет возвращено сообщение об ошибке со специфическим кодом (CO_E_SERVER_STOPPING ). Когда SCM обнаруживает этот специфический код, он просто запускает новый экземпляр серверного процесса и повторяет запрос, как только новый серверный процесс зарегистрирует себя. Несмотря на системы защиты, используемые библиотекой COM, остается вероятность того, что поступающий активационный запрос будет выполняться одновременно с заключительным вызовом функции CoReleaseServerProcess. Чтобы избежать этого, сервер может явно возвратить CO_E_SERVER_STOPPING как из IClassFactory::Create Instance, так и из IPersistFile::Load в том случае, если он определит, что по окончании запроса на прекращение работы был сделан еще какой-то запрос. Следующий код демонстрирует этот способ:

STDMETHODIMP MyClassObject::CreateInstance(IUnknown *puo, REFIID riid, void **ppv) {

LockModule();

// ensure we don't shut down while in call

// убеждаемся в том, что не прекращаем работу

// во время вызова

HRESULT hr; *ppv = 0;

// shutdown initiated?

// процесс останова запущен?

DWORD dw = WaitForSingleObject(g_heventShutdown, 0);

if (dw == WAIT_OBJECT_0) hr = CO_E_SERVER_STOPPING;

else {

// normal CreateInstance implementation

// нормальная реализация CreateInstance

}

UnlockModule();

return hr;

}

Во время написания этого текста ни одна из коммерческих библиотек классов COM не реализовывала этот способ.

Снова о времени жизни сервера

В примере, показанном в предыдущем разделе, не было точно показано, как и когда должен прекратить работу серверный процесс. В общем случае серверный процесс сам контролирует свое время жизни и может прекратить работу в любой выбранный им момент. Хотя для серверного процесса и допустимо неограниченное время работы, большинство из них предпочитают выключаться, когда не осталось неосвобожденных ссылок на их объекты или объекты класса. Это аналогично стратегии, используемой большинством внутрипроцессных серверов в их реализации DllCanUnloadNow. Напомним, что в главе 3 говорилось, что обычно сервер реализует две подпрограммы, вызываемые в качестве интерфейсных указателей, которые запрашиваются и освобождаются внешними клиентами:

// reasons to remain loaded

// причины оставаться загруженными

LONG g_cLocks = 0;

// called from AddRef + IClassFactory::LockServer(TRUE)

// вызвано из AddRef + IClassFactory::LockServer(TRUE)

void LockModule(void) {

InterlockedIncrement(&g_cLocks);

}

// called from Release + IClassFactory::LockServer(FALSE)

// вызвано из Release + IClassFactory::LockServer(FALSE)

void UnlockModule(void) { InterlockedDecrement(&g_cLocks);

}

Это сделало реализацию DllCanUnloadNow предельно простой:

STDAPI DllCanUnloadNow()

{

return g_cLocks ? S_FALSE : S_OK;

}

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

Имеются некоторые различия в том, как ЕХЕ-серверы прекращают работу серверов. Во-первых, обязанностью серверного процесса является упреждающее инициирование процесса своего выключения. В отличие от внутрипроцессных серверов, здесь не существует «сборщика мусора», который запросил бы внепроцессный сервер, желает ли он прекратить работу. Вместо этого серверный процесс должен в подходящий момент явно запустить процесс своего выключения. Если для выключения сервера используется событие Win32 Event, то процесс должен вызвать API-функцию SetEvent:

void UnlockModule(void) {

if (InterlockedDecrement(&g_cLocks) ==0) {

extern HANDLE g_heventShutdown;

SetEvent(g_heventShutdown);

}

}

Если вместо серверного основного потока обслуживается очередь событий Windows MSG, то для прерывания цикла обработки сообщений следует использовать некоторые из API-функций. Проще всего использовать PostThreadMessage для передачи в основной поток сообщения WM_QUIT:

void UnlockModule(void) {

if (InterlockedDecrement(&g_cLocks) == 0) {

extern DWORD g_dwMainThreadID;

// set from main thread

// установлено из основного потока

PostThreadMessage(g_dwMainThreadID, WNLQUIT, 0, 0);

}

}

Если серверный процесс на основе STA знает, что он никогда не будет создавать дополнительные потоки, то он может использовать несколько более простую API-функцию PostQuitMessage:

void UnlockModule(void) {

if (InterlockedDecrement(&g_cLocks) == 0) PostQuitMessage(0);

}

Этот способ работает только при вызове из главного потока серверного процесса.

Второе различие в управлении временем жизни внутрипроцессного и внепроцессного сервера связано с тем, что должно поддерживать сервер в загруженном или работающем состоянии. В случае внутрипроцессного сервера такой силой обладают неосвобожденные ссылки на объекты и неотмененные вызовы IClassFactory::LockServer(TRUE). Неосвобожденные ссылки на объекты необходимо рассмотреть в контексте внепроцессного сервера.

Безусловно, сервер должен оставаться доступным до тех пор, пока внешние клиенты имеют неосвобожденные ссылки на объекты класса сервера. Для внутрипроцессного сервера это реализуется следующим образом:

STDMETHODIMP_(ULONG) MyClassObject::AddRef(void) {

LockModule();

// note outstanding reference

// отмечаем неосвобожденную ссылку

return 2;

// non-heap-based object

// объект, размещенный не в «куче»

}

STDMETHODIMP_(ULONG) MyClassObject::Release(void) {

UnlockModule();

// note destroyed reference

// отмечаем уничтоженную ссылку

return 1;

// non-heap-based object

// объект, размещенный не в «куче»

}

Такое поведение является обязательным, поскольку если DLL выгружается, несмотря на оставшиеся неосвобожденные ссылки на объекты класса, то даже последующие вызовы метода Release приведут клиентский процесс к гибели.

К сожалению, предшествующая реализация AddRef и Release не годится для внепроцессных серверов. Напомним, что после входа в апартамент COM первое, что делает типичный внепроцессный сервер, – регистрирует свои объекты класса с помощью библиотеки COM путем вызова CoRegisterClassObject. Тем не менее, пока таблица класса сохраняет объект класса, существует по меньшей мере одна неосвобожденная ссылка COM на объект класса. Это означает, что после регистрации своих объектов класса счетчик блокировок всего модуля будет отличен от нуля. Эти самоустановленные (self-imposed) ссылки не будут освобождены до вызова серверным процессом CoRevokeClassObject. К сожалению, типичный серверный процесс не вызовет CoRevokeClassObject до тех пор, пока счетчик блокировок всего модуля не достигнет нуля, что означает, что серверный процесс никогда не прекратится.

1 ... 76 77 78 79 80 81 82 83 84 ... 118 ВПЕРЕД
Перейти на страницу:
Комментариев (0)
название