Вопрос про маршалинг
От: MortizW  
Дата: 21.05.06 15:55
Оценка:
Всем привет. Может то наступал уже на такие грабли:


Есть некоторый = интерфейс ISomeClass. Потоковая модель — apparment

Объект этого класса может порождать рабочие потоки. Естественно, указетель в рабочий поток проходит через процедуру маршилинга:


// маршалим
CoMarshalInterThreadInterfaceInStream(__uuidof(ISomeClass),
                                     reinterpret_cast<LPUNKNOWN>(this),
                                     &p_stream);

...

Worker::Execute(...)
{
  // демаршалим объект в рабочем потоке:
  CComPtr<ISomeClass> p_some_class;
  hr = ::CoGetInterfaceAndReleaseStream(p_stream, __uuidof(ISomeClass), (void**) &p_some_class);
  ...
}


Теперь, собственно в чем проблемма :

При уничтожении ISomeClass в методе FinalRelease (я использую ATL) проиходит уничножение пула потоков. Последовательно гасятся все рабочие потоки, но если это просиходит в момент Worker::Execute(...) то получается deadlock, т.к. с одной сотороны объект разрушается в основном потоке, а с другой стороны при выходе из области видимости загшлушки CComPtr<ISomeClass> p_some_class тоже вызывается Release, который так же переадресовывается основному объекту. Соотвественно, рабочий поток, нормальным образом завершится не может.

Мне пока пришла у меня 2 идеи как этого избежать:

1. проставлять какой-нить флаг, в рабочем потоке делать так :

Worker::Execute(...)
{
   if (p_some_class.destorying)
   {
       p_some_class.Detach(); // чтобы избежать вызова Release()
   }
}


но так вроде будет лик?

или еще
2. Вариант перекрыть Release для ISomeClass и вызывать остановку рабочих потоков,раньше, но не понятно, когда именно

Что многоуважаемый All думает по этому поводу?

Заранее — благдарю
Re: Вопрос про маршалинг
От: MortizW  
Дата: 22.05.06 18:44
Оценка: -1
К сожалению, никто не отктил, но решение я нашел такое :


class SafeIterfaceReleaser
{
    IUnknown* m_ptr;
public : 

    IUnknown** operator&()
    {
        return &m_ptr;
    }


    SafeIterfaceReleaser() 
        : m_ptr(NULL)
    {

    }

    bool operator !()
    {
        return (m_ptr == NULL);
    }

    SafeIterfaceReleaser(IUnknown* ptr) 
        : m_ptr(ptr)
    {
       
    }

    void Attach(IUnknown* ptr)
    {
        m_ptr = ptr;
    }

    IUnknown* GetPtr()
    {
        return  m_ptr;
    }


    ~SafeIterfaceReleaser()   
    {
        DWORD tid;
        HANDLE hndl = ::CreateThread(0, 0, thread_proc, m_ptr, 0, &tid);
        CloseHandle(hndl);
    }
private:

    static DWORD WINAPI thread_proc(LPVOID lpParameter)
    {
        if (!lpParameter)
            return 0;

        IUnknown* ptr 
            = reinterpret_cast<IUnknown*>(lpParameter);
        ATLASSERT(ptr);
        ptr->Release();
        return 0;
    }
};



освобождаем интерфейс в 3-м потоке и все работает
Re: Вопрос про маршалинг
От: Константин Л.  
Дата: 23.05.06 08:53
Оценка:
Здравствуйте, MortizW, Вы писали:

[]

MW>Теперь, собственно в чем проблемма :


MW>При уничтожении ISomeClass в методе FinalRelease (я использую ATL) проиходит уничножение пула потоков. Последовательно гасятся все рабочие потоки, но если это просиходит в момент Worker::Execute(...) то получается deadlock, т.к. с одной сотороны объект разрушается в основном потоке, а с другой стороны при выходе из области видимости загшлушки CComPtr<ISomeClass> p_some_class тоже вызывается Release, который так же переадресовывается основному объекту. Соотвественно, рабочий поток, нормальным образом завершится не может.


Почему не может нормально завершиться? По идее заглушка должна следить за своим объектом. Все должно само разруливаться.
Попробуй не ручками маршалить, а через GIT
Re: Вопрос про маршалинг
От: Tom Россия http://www.RSDN.ru
Дата: 23.05.06 14:10
Оценка: 9 (1)
MW>Что многоуважаемый All думает по этому поводу?
После того, как ты в FinalRelease послал своим потокам евент о том, что надо завершиться — нужно ждать эти потоки с циклом выборки сообщений, CoWaitForMultipleHandles,AtlWaitWithMessageLoop, MsgWaitForMultipleObjects

А решение с отдельным потоком — изврат

И ещё вопрос, а какого у тебя вообще происходит разрушение обьекта, если потоки держат на него ссылку?
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
Народная мудрось
всем все никому ничего(с).
Re[2]: Вопрос про маршалинг
От: Tom Россия http://www.RSDN.ru
Дата: 23.05.06 14:10
Оценка:
КЛ>Попробуй не ручками маршалить, а через GIT
Никакой разници нет
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
Народная мудрось
всем все никому ничего(с).
Re[3]: Вопрос про маршалинг
От: Константин Л.  
Дата: 23.05.06 14:54
Оценка:
Здравствуйте, Tom, Вы писали:

КЛ>>Попробуй не ручками маршалить, а через GIT

Tom>Никакой разници нет

Ну вроде как через него удобней
Re[2]: Вопрос про маршалинг
От: MortizW  
Дата: 23.05.06 17:53
Оценка:
Здравствуйте, Tom, Вы писали:

MW>>Что многоуважаемый All думает по этому поводу?

Tom>После того, как ты в FinalRelease послал своим потокам евент о том, что надо завершиться — нужно ждать эти потоки с циклом выборки сообщений, CoWaitForMultipleHandles,AtlWaitWithMessageLoop, MsgWaitForMultipleObjects

Tom>А решение с отдельным потоком — изврат


Tom>И ещё вопрос, а какого у тебя вообще происходит разрушение обьекта, если потоки держат на него ссылку?


Да, как и ожидалось фикс неудался. Не знаю, может это и какой-нибуть баг CThreadPool, но это вряд ли

Как так получается, что проихводит разрушение объекта — честно говоря не знаю. Думал, что это нормальное поведение. Т.к. заглушка существуюет сама по себе, а галвный объект — сам по себе.


Кст. если CoGetInterfaceAndReleaseStream, размерашаленному указателю не делать ->release. Это будет лик?
Re[3]: Вопрос про маршалинг
От: Tom Россия http://www.RSDN.ru
Дата: 23.05.06 18:55
Оценка:
MW>Кст. если CoGetInterfaceAndReleaseStream, размерашаленному указателю не делать ->release. Это будет лик?
конечно
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
Народная мудрось
всем все никому ничего(с).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.