Для предотвращения взаимоблокировки все типы апартаментов СОМ поддерживают реентерабельность (повторную входимость)[1]. Когда поток в апартаменте делает запрос на объект вне апартамента вызывающего объекта посредством заместителя, то могут обслуживаться и другие поступающие запросы методов, пока поток вызывающего объекта находится в ожидании ORPC-ответа па первый запрос. Без этой поддержки было бы невозможно создавать системы, основанные на совместно работающих объектах. При написании следующего кода предполагалось, что
ICallback *pcb = 0;
HRESULT hr = CoCreateInstance(CLSID_Callback, 0, CLSCTX_ALL,
IID_ICallback, (void**)&pcb);
assert(SUCCEEDED(hr));
// callback object lives in this apt.
// объект обратного вызова живет в этом апартаменте
I0bject "po = 0;
hr = CoCreateInstance(CLSID_Object, 0, CLSCTX_REMOTE_SERVER,
IID_Iobject, (void **)&po);
assert(SUCCEEDED(hr));
// object lives in different apt.
// объект живет в другом апартаменте
// make a call to remote object, marshaling a reference to
// the callback object as an [in] parameter
// делаем вызов удаленного объекта, маршалируя ссылку
// на объект обратного вызова как на [in]-параметр
hr = po->UseCallback(pcb);
// clean up resources
// очищаем ресурсы
pcb->Release();
pco->Release();
На рис. 5.6 показано, что если апартамент вызывающего объекта не поддерживает реентерабельность, то следующая реализация метода
STDMETHODIMP Object::UseCallback(ICallback *pcb) {
HRESULT hr = pcb->GetBackToCallersApartment();
assert(SUCCEEDED(hr));
return S_OK;
Напомним, что когда
STDMETHODIMP Object::UseCallback(ICallback *pcb) {
if (!pcb) return E_INVALIDARG;
// hold onto proxy for later use
// сохраняем в заместителе для дальнейшего использования
(m_pcbMyCaller = pcb)->AddRef();
return S_OK; }
Обратное соединение с апартаментом клиента будет длиться до тех пор, пока заместитель не будет освобожден объектом. Поскольку все апартаменты СОМ могут получать ORPC-запросы, объект может послать обратный вызов в апартамент клиента в любое время.
Реентерабельность реализуется для каждого типа апартаментов по-разному. Наиболее проста реализация в случае МТА, так как МТА-апартаменты не гарантируют параллелизма и не указывают, какой поток будет обслуживать заданный вызов метода. Повторный вызов может прийти в то время, когда МТА-поток заблокирован в канале в ожидании ORPC-ответа. Тогда RPC-поток, получающий повторный запрос, просто входит в МТА и обслуживает вызов своими ресурсами. Тот факт, что другой поток апартамента заблокирован и ожидании ORPC-ответа, не влияет на диспетчеризацию вызова. В случае реализации RTA – когда поток, выполняющийся в RTA, делает межапартаментный вызов посредством заместителя, – канал уступает контроль над апартаментом, снимая блокировку всего RTA и разрешая тем самым обработку поступивших вызовов. И снова, но причине отсутствия привязки объектов к потокам в RTA, RPC-поток, получающий ORPC-запрос, может просто войти в апартамент RTA и обслужить вызов сразу после блокирования всего RTA.