Чтение онлайн

на главную - закладки

Жанры

Интернет-журнал "Домашняя лаборатория", 2007 №6
Шрифт:

10. В том же диалоге на вкладке Link в поле Object/library moduls добавить через пробел ссылки на библиотеки поддержки удаленного вызова процедур rpcndr.lib, rpcns4.lib, rpcrt4.lib.

11. Откомпилировать проект и зарегистрировать построенную DLL прокси/заглушки с помощью Tools|Register Control.

В процессе саморегистрации построенной DLL прокси/заглушки она получает CLSID равный CLSID интерфейса IPub. Под соответствующим ключом реестре имеется раздел InProcServer32 с параметром по умолчанию, задающим путь к построенной DLL. Кроме того, регистрируются

все три интерфейса под ключом HKEY_CLASES_ROOT Interface. Интерфейсы регистрируются под своими собственными идентификаторами (GUID). Для каждого имеется подраздел NumMethods, в котором указывается число методов интерфейса (включая наследуемые), и подраздел ProxyStabClsid32, в котором указывается GUID для DLL прокси/заглушки.

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

Говоря про маршалинг следует остановиться на вопросе передачи данных между клиентом и сервером. В случае, когда передаются, например, массивы, необходимо следить за тем, кто выделяет и освобождает память, сколько выделяется памяти. Приведенные ниже примеры взяты из работы Richard Grimes, "Marshaling Your Data: Efficient Data Transfer Techniques Using COM and Windows 2000", MSDN Magazine, September 2000.

Предположим, что некоторый интерфейс включает методы, описания которых на IDL приведено ниже

HRESULT PassLongs([in] ULONG ulNum,

[in, size_is(ulNum)] LONG* pArrln);

HRESULT GetLongs([in] ULONG ulNum,

[out, size_is(ulNum)] LONG* pArrOut);

Здесь от клиента к объекту и обратно передаются массивы. Проще всего случай передачи массива от клиента к объекту. В этом случае клиент сам выделяет память под массив и сам ее освобождает. При передаче массива от объекта к клиенту возможны два варианта. В первом клиент заранее, до вызова метода знает размер передаваемого массива, во втором этот размер сообщает объект уже после вызова метода. Рассмотрим обе эти возможности.

Начнем со случая, когда клиент до вызова метода имеет информацию о размере массива. Код клиента

ULONG ulNum = 10;

LONG 1 [10];

hr = pArrObj — > GetLongs(ulNum, 1);

Код сервера

STDMETHODIMP CArrays::GetLongs(ULONG ulNum, LONG* pArr)

{

for (ULONG x = 0; x < ulNum; x++) pArr[x] = x;

return S_OK;

}

Как все это работает. Клиент сам выделяет память под массив в виде стековой переменной. Это позволяет ему не заботится об ее освобождении. Маршалер (система объектов, обеспечивающая маршализацию данных, передаваемых между клиентом и сервером) как на стороне клиента, так и на стороне объекта имеет информацию о размере передаваемого массива еще до возврата из метода. Это позволяет ему выделить на стороне объекта память под этот массив и передать указатель на выделенную память объекту (рАгг). Объект заполняет массив данными, после чего эти данные передаются по каналу клиенту. После передачи данных маршалер сам освобождает выделенную на стороне объекта память.

Во втором случае клиент получает размер массива уже после вызова метода. На IDL описание метода выглядит следующим образом

HRESULT GetLongsAlloc([out] ULONG* pNum, [out, size_is(, *pNum)] LONG** ppArr);

Здесь запятая в size is говорит о том, что *pNum есть размер массива, УКАЗАТЕЛЬ на который есть ppArr.

В

данном случае маршалер не может сам выделить память под массив на стороне объекта и, следовательно, это должен делать объект. Но освобождать выделенную память после передачи данных должен уже маршалер, т. к. объект к этому моменту уже завершит работу. Для выделения и освобождения памяти в данном случае следует использовать функции CoTaskMemAlloc и CoTaskMemFree , которые может вызывать и маршалер.

Код компонента

STDMETHODIMP CArrays::GetLongsAlloc(ULONG* pNum, LONG** ppArr);

{

*pNum = 10;

*ppArr = reinterpret_cast<LONG*>(CoTaskMemAlloc(*pNum * sizeof(LONG)));

for (ULONG x = 0; x < *pNum; x++) (*ppArr)[x] = x;

return S_OK;

}

Здесь reinterpret_cast<LONG*> используется для приведения типа указателя, возвращаемого при выделении памяти, к указателю на long. Освобождает выделенную память сам маршалер, вызывая CoTaskMemFree.

На стороне клиента память выделяет маршалер, получив информацию о размере массива — *pNum. Освобождает же эту память клиент

ULONG ulNum;

LONG* pi;

hr = pArrObj —> GetLongsAlloc(SulNum, &pl);

for (ULONG ul = 0; ul < ulNum; ul++)

printf("%ld\n", pi[ul]);

CoTaskMemFree(pi);

Потоковая модель и апартаменты

Процесс и поток

Прежде всего вспомним некоторые понятия, связанные с процессами и потоками.

Приложение — это один или несколько процессов.

Каждый процесс имеет ряд ресурсов, среди которых виртуальное адресное пространство процесса, исполняемый код, данные, дескрипторы объектов, переменные среды, базовый приоритет. Таким образом, процесс это скорее среда, в которой выполняется один или несколько потоков.

Поток — выполнение последовательности машинных команд. Потоки, живущие в одном процессе, делят все его ресурсы. Кроме того, каждый поток имеет и свои собственные, доступные только ему ресурсы-локальная память потока.

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

Очередь потоков регулируется с помощью их приоритетов. Для каждого уровня приоритета имеется своя очередь. Переключение контекста (прерывание исполняемого потока и выполнение нового) происходит при возникновении одного из трех событий:

• закончился квант времени, выделенный потоку;

• готов к выполнению поток с более высоким приоритетом;

• исполняемый поток перешел в состояние ожидания.

Базовый приоритет потока определяется двумя величинами: приоритетом процесса и приоритетом потока в рамках данного процесса. Очередность определяется не базовым, а динамическим приоритетом. Часто динамический приоритет просто совпадает с базовым, но в некоторых случаях система может приписать потоку динамический приоритет, превосходящий его базовый приоритет.

Поделиться:
Популярные книги

Ванька-ротный

Шумилин Александр Ильич
Фантастика:
альтернативная история
5.67
рейтинг книги
Ванька-ротный

Зубы Дракона

Синклер Эптон Билл
3. Ланни Бэдд
Проза:
историческая проза
5.00
рейтинг книги
Зубы Дракона

Мымра!

Фад Диана
1. Мымрики
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Мымра!

Наследник

Майерс Александр
3. Династия
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Наследник

Идеальный мир для Лекаря 21

Сапфир Олег
21. Лекарь
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 21

На осколках разбитых надежд

Струк Марина
Любовные романы:
исторические любовные романы
5.00
рейтинг книги
На осколках разбитых надежд

Поле боя – Земля

Хаббард Рональд Лафайет
Фантастика:
научная фантастика
7.15
рейтинг книги
Поле боя – Земля

На границе империй. Том 7. Часть 4

INDIGO
Вселенная EVE Online
Фантастика:
боевая фантастика
космическая фантастика
5.00
рейтинг книги
На границе империй. Том 7. Часть 4

Чехов

Гоблин (MeXXanik)
1. Адвокат Чехов
Фантастика:
фэнтези
боевая фантастика
альтернативная история
5.00
рейтинг книги
Чехов

Госпожа Доктор

Каплунова Александра
Фантастика:
попаданцы
фэнтези
5.00
рейтинг книги
Госпожа Доктор

Черный дембель. Часть 1

Федин Андрей Анатольевич
1. Черный дембель
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Черный дембель. Часть 1

Пророк, огонь и роза. Ищущие

Вансайрес
Фантастика:
фэнтези
5.00
рейтинг книги
Пророк, огонь и роза. Ищущие

Шайтан Иван

Тен Эдуард
1. Шайтан Иван
Фантастика:
боевая фантастика
попаданцы
альтернативная история
5.00
рейтинг книги
Шайтан Иван

Ротмистр Гордеев

Дашко Дмитрий Николаевич
1. Ротмистр Гордеев
Фантастика:
фэнтези
попаданцы
альтернативная история
5.00
рейтинг книги
Ротмистр Гордеев