Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Роджерсон Д. - Основы COM - 2000.pdf
Скачиваний:
411
Добавлен:
13.08.2013
Размер:
2.4 Mб
Скачать

215

Изменения в компоненте

Помимо добавления к компоненту нескольких методов мы также должны сделать его «потокобезопасным». В конце концов, у нас два разных потока одновременно увеличивают и уменьшают один счетчик. Для того, чтобы обеспечить защиту компонента, я ввел простой класс CsimpleLock:

class CSimpleLock

{

public:

//Заблокировать

CSimpleLock(HANDLE hMutex)

{

m_hMutex = hMutex; WaitForSingleObject(hMutex, INFINITE);

}

//Разблокировать

~CSimpleLock()

{

ReleaseMutex(m_hMutex);

}

private:

HANDLE m_hMutex; };

Конструктору CSimpleLock передается описатель мьютекса. Конструктор не возвращает управление, пока не дождется мьютекса. Деструктор CsimpleLock освобождает мьютекс, когда поток управления выходит из области действия переменной. Для защиты функции нужно просто создать объект CSimpleLock:

HRESULT __stdcall CA::Tick(int delta)

{

CSimpleLock Lock(m_hCountMutex);

m_count += delta; return S_OK;

}

HRESULT __stdcall CA::Left()

{

CSimpleLock Lock(m_hHandMutex);

m_bRightHand = FALSE; return S_OK;

}

Наш компонент использует два разных мьютекса — m_hHandMutex и m_hCountMutex. Один из них защищает счетчик, а второй — переменную, указывающую сторону. Наличие двух разных мьютексов позволяет одному потоку работать с переменной, указывающей сторону, пока второй работает со счетчиком. Доступ к компонентам в подразделении возможен только для одного потока — потока этого подразделения. Если бы компонент выполнялся в потоке подразделения, один поток не смог бы вызвать Left, если другой уже вызывает Tick. Однако при использовании свободных потоков синхронизация возлагается на разработчика компонента, который может использовать свое знание внутреннего устройства компонента для оптимальной синхронизации.

Оптимизация маршалинга для свободных потоков

Как маршалинг, так и синхронизация работают медленно. Если возможно, избегайте их. Одно из правил, связанных с разделенными потоками, — необходимость маршалинга интерфейсов перед передачей разделенным потокам. Но предположим, что клиент в разделенном потоке хочет использовать интерфейс компонента свободных потоков в том же самом процессе. Нам в действительности не нужен маршалинг, так как процесс один и тот же. Нам также не нужна синхронизация вызовов нашего компонента, выполняемая СОМ; в конце концов, мы сделали компонент «потокобезопасным», чтобы его можно было использовать из нескольких потоков одновременно. Похоже, компоненты в свободном потоке должны уметь напрямую передавать указатели на интерфейсы другим разделенным потокам в том же самом процессе. Да, они это умеют.

Оптимизация не просто возможна — библиотека СОМ еще и предоставляет специальный агрегируемый компонент, который выполнит для Вас эту оптимизацию. CoCreateFreeThreadedMarshaler создает компонент с интерфейсом IMarshal, который определяет, находится ли клиент интерфейса в том же самом процессе. Если это так, то при маршалинге указатели передаются без изменений. Если клиент находится в другом процессе, то

Соседние файлы в предмете Программирование на C++