Контрольная работа: Распределенная обработка данных
Вместо того, чтобы удалять компоненты напрямую, мы будем сообщать компоненту, что нам нужен интерфейс или что мы закончили с ним работать. Мы точно знаем, когда начинаем использовать интерфейс, и знаем (обычно), когда перестаем его использовать. Однако, как уже ясно, мы можем не знать, что закончили использовать компонент вообще. Поэтому имеет смысл ограничиться сообщением об окончании работы с данным интерфейсом — и пусть компонент сам отслеживает, когда мы перестаем пользоваться всеми интерфейсами.
Именно для реализации этой стратегии и предназначены еще две функции-члена IUnknown — AddRef и Release.
определение интерфейса IUnknown:
interface IUnknown
{
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) = 0;
virtual ULONG __stdcall AddRef() = 0;
virtual ULONG __stdcall Release() = 0;
};
AddRef и Release реализуют и технику управления памятью, известную как подсчет ссылок (reference counting).
Подсчет ссылок — простой и быстрый способ, позволяющий компонентам самим удалять себя. Компонент СОМ поддерживает счетчик ссылок. Когда клиент получает некоторый интерфейс, значение этого счетчика увеличивается на единицу. Когда клиент заканчивает работу с интерфейсом, значение на единицу уменьшается. Когда оно доходит до нуля, компонент удаляет себя из памяти. Клиент также увеличивает счетчик ссылок, когда создает новую ссылку на уже имеющийся у него интерфейс. Как Вы, вероятно, догадались, увеличивается счетчик вызовом AddRef, а уменьшается — вызовом Release.
Для того, чтобы пользоваться подсчетом ссылок, необходимо знать лишь три простых правила:
1. Вызывайте AddRef перед возвратом. Функции, возвращающие интерфейсы, перед возвратом всегда
должны вызывать AddRef для соответствующего указателя. Это также относится к QueryInterface и функции CreateInstance. Таким образом, Вам не нужно вызывать AddRef в своей программе после получения (от функции) указателя на интерфейс.
2. По завершении работы вызывайте Release. Когда Вы закончили работу с интерфейсом, следует вызвать для него Release.
3. Вызывайте AddRef после присваивания. Когда бы Вы ни присваивали один указатель на интерфейс другому, вызывайте AddRef. Иными словами: следует увеличить счетчик ссылок каждый раз, когда создается новая ссылка на данный интерфейс.
Приведенный ниже фрагмент кода создает компонент и получает указатель на интерфейс IX. Мы не вызываем AddRef, так как за нас это делают CreateInstance и QueryInterface. Однако мы вызываем Release как для интерфейса IUnknown, возвращенного CreateInstance, так и для интерфейса IX, возвращенного QueryInterface.
// Создать компонент
IUnknown* pIUnknown = CreateInstance();
// Получить интерфейс IX
IX* pIX = NULL;
HRESULT hr = pIUnknown->QueryInterface(IID_IX, (void**)&pIX);
if (SUCCEEDED(hr))
{
pIX->Fx(); // Использовать интерфейс IX
pIX->Release(); // Завершить работу с IX
}
pIUnknown->Release(); // Завершить работу с Iunknown
В приведенном выше примере мы фактически закончили работать с IUnknown сразу же после вызова