Re: Шаблон проектирования “Одиночка” (Singleton) в ATL прило
От: lext Украина www.mira-tech.com.ua
Дата: 25.01.04 13:34
Оценка: 3 (1)
Здравствуйте, Иван Андреев, Вы писали:

ИА>Статья:



ИА>Авторы:

ИА> Иван Андреев

Отличная статья! Содержащийся в ней материал почти что полностью исчерпывает тему. Я говорю "почти" потому, что проблема маршаллинга так и осталась не решенной в случае использования STA. Но стоит ли ее решать при помощи маршаллинга?

Допустим, клиентский STA1 вызывает метод синглетона, инициализированного в STA2.
Давайте сравним следующие три способа реализации этого вызова:

1) Это делается через код Proxy/Stub, который использует SendMessage, чтобы синглетон выполнил этот метод в контексте STA2.

2) Proxy/Stub не используется, метод синглетона вызывается напрямую. Реализация метода использует крититическую секцию для разделения доступа из различных STA. Тело метода выполняется в контексте STA1.

3) Proxy/Stub не используется, метод синглетона вызывается напрямую. Реализация метода использует SendMessage, чтобы переключиться в контекст STA2. Основное тело метода выполняется в контексте STA2. Синглетон инкапсулирует STA2, и полностью контролирует время его жизни (такие объекты называют активными).


Если синглетон не контролирует время жизни STA2, то способ 1) принципиально неприменим. В противном случае лучше подходит способ 3) — если это не так, стоит всерьез задуматься о необходимости рефакторинга .
Если же сиглетон не зависит от того, в каком STA он был инициализирован, то способ 2) подходит идеально.


Теперь о синглетоне-фениксе, а если точнее, то о проблеме потери сотояния синглетона после его разрушения при обнулении счетчика ссылок.
А кто сказал, что синглетон обязательно нужно разрушать? Не лучше ли вместо разрушения/создания использовать деактивацию/активацию? вот, например, участок кода, который написан с использованием библиотеки ComXLib:


class MyServer:
    public atl_com_object_root<>,
    public CComCoClass<MyServer, &CLSID_MyServer>,
    public IMyServer
{
private:
    thread    m_thread; // incapsulates STA
    /* ...;
    */

        // prefix "inside" means that function mus be called inside incapsulated STA
    void insideActivate();
    void insideDeactivate();
    void insideDoSomething(SomeType1 arg1, SomeType2 arg2, SomeType3 arg3);
public:
    /* ...;
    */
    TX_DECLARE_ATL_SINGLETON(MyServer);
    
    void on_reffed()
    {
        if(!m_thread.is_still_active())
            m_thread.start();
        m_thread.execute_member_0(this, MyServer::insideActivate);
    }

    void on_unreffed()
    {
        _ASSERTE(m_thread.is_still_active());
        m_thread.execute_member_0(this, MyServer::insideDeactivate);
    }
    /* ...;
    */

    STDMETHOD(DoSomething)(SomeType1 arg1, SomeType2 arg2, SomeType3 arg3)
    {
        itf_exception<IMyServer> ex;
        TX_TRY_EX{
            m_thread.execute_member_3(this, MyServer::insideDoSomething, arg1, arg2, arg3);
        }TX_END_TRY_EX(ex);
        return ex.push();
    }
};


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