Методы IUnknown::AddRef() и IUnknown::Release() 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Методы IUnknown::AddRef() и IUnknown::Release()



За управление временем жизни компонентов отвечают два метода интерфейса IUnknown: AddRef() и Release(). Обычно СОМ-компонент имеет несколько интерфейсов, каждый из которых может быть связан со многими внешними клиентами. Обратите внимание на то, что в нашем примере компонент в действительности является классом C++, а в данный момент мы обсуждаем управление временем жизни определенного экземпляра класса. Пользователь будет создавать экземпляр с помощью некоторого механизма, который мы еще обсудим, и использовать возможности этого экземпляра посредством его СОМ-интерфейсов. Первоначально экземпляр будет создан с помощью оператора C++ new, а затем мы попытаемся определить, когда этот экземпляр может быть удален.

Поскольку экземпляр СОМ-компонента может иметь несколько интерфейсов, связанных со многими клиентами, нашему объекту необходимо иметь некоторую возможность подсчета обращений к нему (счетчик). Всякий раз, когда клиент запрашивает интерфейс, значение счетчика будет увеличиваться, а когда клиент завершает работу с интерфейсом — уменьшаться. В конце концов, когда значение счетчика обращений станет равным нулю, СОМ-компонент будет уничтожен. Именно для этого и служат методы IUnknown::AddRef() и IUnknown::Release().

Таким образом, в рассматриваемом нами примере класса Math требуется отслеживать значение внутреннего счетчика обращений. Назовем этот счетчик m_lRef. Когда компонент по запросу клиента возвращает интерфейс, значение счетчика будет увеличиваться, а по окончании использования интерфейса клиент уменьшает это значение посредством вызова IUnknown::Release().

Пользователь компонента не может непосредственно удалить экземпляр С++-объекта, поскольку в его распоряжении имеется только указатель на виртуальную таблицу функций C++. В действительности клиент не имеет права удалять объект в любом случае, поскольку могут существовать другие клиенты, использующие тот же компонентный объект. Только сам компонент, основываясь на значении своего внутреннего счетчика обращений, может определить момент своего удаления. Ниже приводится текст программы компонента Math с включением реализации интерфейса IUnknown.

class Math: public IMath { public: HRESULT QueryInterface(REFIID riid, void** ppv); ULONG AddRef(); ULONG Release();   long Add(long Op1, long Op2); long Subtract(long Op1, long Op2); long Multiply(long Op1, long Op2); long Divide (long Op1, long Op2);   // Реализация private: // Новая переменная-член класса добавлена для подсчета // обращений извне к интерфейсу объекта DWORD m_lRef;   public: Math(); };   Math::Math() { m_lRef = 0; } HRESULT Math::QueryInterface(REFIID riid, void** ppv) { switch(riid) { case IID_IUnknown: case IID_IMath; *ppv = this; // Поскольку мы возвращаем новый указатель на // интерфейс, необходимо вызвать метод AddRef AddRef(); return (S_OK);   default: return (E_NOINTERFACE); } }   // Реализация функии IUnknown:Release ULONG Math::Release() { InterlockedDecrement(&m_lRef);   // когда значение счетчика обращений // становится равным нулю, объект удаляет сам себя if (m_lRef == 0) { delete this; // нельзя вернуть m_lRef, поскольку его уже не существует return 0; } else return m_lRef; }   // Реализация функции IUnknown::AddRef ULONG Math::AddRef() { InterlockedIncrement(&m_lRef); return m_lRef; }

Для реализации функций AddRef() и Release(), унаследованных от класса IUnknown, мы ввели переменную-член m_lRef, которая отвечает за подсчет текущих обращений к объекту или ожидающих обработки указателей интерфейса. Хотя функции AddRef () и Release () могут изменять значение счетчика обращений к СОМ-интерфейсу, сам интерфейс не является экземпляром объекта. Объект в каждый момент времени может иметь любое количество пользователей своих интерфейсов и должен отслеживать значение внутреннего счетчика активных интерфейсов. Если это значение достигает нуля, объект сам себя удаляет.

Очень важно правильно и своевременно использовать методы AddRef () и Release(). Эта пара функций аналогична паре операторов new и delete, используемых в языке C++ для управления памятью. Как только пользователь получает новый указатель на интерфейс или присваивает его значение какой-либо переменной, необходимо вызывать AddRef (). В данном случае следует быть очень внимательным, поскольку некоторые функции СОМ-интерфейсов возвращают указатели на другие интерфейсы и в таких случаях сами вызывают метод AddRef() для возвращаемого указателя. Наиболее наглядным примером этого является метод QueryInterface(), в котором AddRef () вызывается при каждом запросе интерфейса и, таким образом, не возникает необходимость в новом вызове метода AddRef ().

ПРИМЕЧАНИЕ В предыдущем примере были использованы библиотечные функции Win32 API InterlockedIncrement и InterlockedDecrement. Это обеспечивает возможность синхронизированного доступа к внутренним счетчикам и делает компонент безопасным в отношении потоков (по крайней мере, с точки зрения управления временем жизни компонента).

Множественные интерфейсы

Одним из наиболее мощных свойств СОМ является то, что каждый компонент может предоставлять и обычно предоставляет несколько интерфейсов для одного объекта. Подумайте над этим еще раз. При разработке С++-класса создается всего один интерфейс. А при создании на основе класса компонента создается как минимум еще один интерфейс. Обычно при построении СОМ-компонента вам необходимо предоставить несколько интерфейсов для одного экземпляра класса C++.

Объявление нескольких интерфейсов для одного класса C++ на первый взгляд не является трудным, но на самом деле может быть очень непростым делом. Во-первых, поскольку СОМ-интерфейсы фактически являются указателями на виртуальную таблицу функций C++, класс с множеством интерфейсов требует создания множества виртуальных таблиц. Другой причиной взаимосвязи компонентных объектов и их классов реализации интерфейса является необходимость подсчета количества обращений. Все интерфейсы СОМ-объекта должны взаимодействовать между собой в обеспечение подсчета обращений. Для каждого объекта существует только один счетчик обращений, и интерфейсы должны использовать его совместно. Эта взаимосвязь осуществляется с помощью множества интерфейсов IUnknown. Запомните, каждый СОМ-компонент должен обладать собственной реализацией интерфейса IUnknown.

 

 



Поделиться:


Последнее изменение этой страницы: 2021-05-27; просмотров: 83; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.117.196.217 (0.004 с.)