Шаблон проектирования “Одиночка” (Singleton) в ATL приложени
От: Иван Андреев Россия www.rsdn.ru
Дата: 18.08.03 13:21
Оценка: 380 (14)
Статья:
Шаблон проектирования “Одиночка” (Singleton) в ATL приложениях
Автор(ы): Иван Андреев
Дата: 03.08.2003
Описание шаблона проектирования синглетон очень простое — синглетон представляет собой единственный экземпляр класса, с которым работают все клиенты. Применительно к COM шаблон проектирования синглетон гарантирует, что все вызовы CoCreateInstance будут возвращать указатель на интерфейс единственного экземпляра компонента. Удобство использования таких компонентов/классов заключается в том, что клиенты работают с одним и тем же экземпляром, а значит, получают доступ к разделяемому состоянию этого экземпляра. Несмотря на простое описание, не существует "идеальной" реализации этого шаблона ни в языке С++, ни для COM-объектов. Связано это с тем, что любая существующая реализация имеет некоторые ограничения и не может выступать в роли "универсальной" реализации на все случаи жизни.


Авторы:
Иван Андреев

Аннотация:
Описание шаблона проектирования синглетон очень простое — синглетон представляет собой единственный экземпляр класса, с которым работают все клиенты. Применительно к COM шаблон проектирования синглетон гарантирует, что все вызовы CoCreateInstance будут возвращать указатель на интерфейс единственного экземпляра компонента. Удобство использования таких компонентов/классов заключается в том, что клиенты работают с одним и тем же экземпляром, а значит, получают доступ к разделяемому состоянию этого экземпляра. Несмотря на простое описание, не существует "идеальной" реализации этого шаблона ни в языке С++, ни для COM-объектов. Связано это с тем, что любая существующая реализация имеет некоторые ограничения и не может выступать в роли "универсальной" реализации на все случаи жизни.
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 корректно осуществляется маршаллинг и обработка исключительных ситуаций.
Re: Шаблон проектирования “Одиночка” (Singleton) в ATL прило
От: SVV Беларусь  
Дата: 12.11.06 15:40
Оценка:
Здравствуйте, Иван Андреев, Вы писали:

...

Попробовал сделать Singleton как Exe сервер:

class ATL_NO_VTABLE CObj : 
    public CComObjectRootEx<CComMultiThreadModel>,
    public CComCoClass<CObj, &CLSID_Obj>,
    public IConnectionPointContainerImpl<CObj>,
    public IDispatchImpl<IObj, &IID_IObj, &LIBID_SINGLETONEXELib>,
    public CProxy_IObjEvents< CObj >
{
  DECLARE_CLASSFACTORY_SINGLETONMARSH(CObj);
public:
...
  STDMETHOD    (MakeEvent (IN BSTR bsName, IN BSTR bsParam, OUT long *pResult));
  STDMETHOD    (put_field (IN long newVal));
  STDMETHOD    (get_field (OUT long *pVal));
  long    m_lfield;
...
}

MakeEvent приводит к генерации события UsedElement (bsName, bsParam)
field — свойство, позволяющее читать и устанавливать внутреннюю переменную m_lfield

Не получается сделать 2 вещи:
1. Хочу одним скриптом (SetNum10.Js) установить значение внутренней переменной в 10, а другим скриптом (ReadNum.Js) прочитать это значение. Сейчас ReadNum.Js получает начальное значение, устанавливаемое в конструкторе CObj вне зависимости от вызова SetNum10.Js
Как побороть? Ведь это значит что объект все-таки не является синглтоном?

2. Хочу запустив N скриптов и вызвав метод MakeEvent в одном из них, получить событие UsedElement в каждом из скриптов. Как добиться такого? Сейчас событие получаю только в том скрипте, в котором вызван метод MakeEvent...

Заранее благодарен за ответы.
Re: Неплохо бы еще уделить внимание событиям..
От: SVV Беларусь  
Дата: 14.11.06 11:16
Оценка:
Здравствуйте, Иван Андреев, Вы писали:
...
События нужно получать и клиентам, соединившимся с синглтоном из скрипта (Client.Js) и клиентам, создавшим синглтон в html странице с помощью <object>.
Re[2]: Шаблон проектирования “Одиночка” (Singleton) в ATL пр
От: s0rc  
Дата: 14.11.06 17:17
Оценка:
Здравствуйте, SVV, Вы писали:

SVV>Здравствуйте, Иван Андреев, Вы писали:


SVV>Попробовал сделать Singleton как Exe сервер:

SVV>1. Хочу одним скриптом (SetNum10.Js) установить значение внутренней переменной в 10, а другим скриптом (ReadNum.Js) прочитать это значение. Сейчас ReadNum.Js получает начальное значение, устанавливаемое в конструкторе CObj вне зависимости от вызова SetNum10.Js
SVV>Как побороть? Ведь это значит что объект все-таки не является синглтоном?

а не получается ли, что хоть он и синглтон, но умирает по окончанию скрипта, а новый скрипт работает с новым синглтоном? ведь никто не говорит, что синглтон есть обязательно (их <=1). поэтому сам сервер должен держать одну ссылку на все время работы (оформить в виде сервиса) (это догоро, но очень просто) или активация и деактивация (дешево и сердито с сохранением состояния).
Re[3]: Шаблон проектирования “Одиночка” (Singleton) в ATL пр
От: SVV Беларусь  
Дата: 15.11.06 07:16
Оценка:
Здравствуйте, s0rc, Вы писали:

...

S>а не получается ли, что хоть он и синглтон, но умирает по окончанию скрипта, а новый скрипт работает с новым синглтоном? ведь никто не говорит, что синглтон есть обязательно (их <=1). поэтому сам сервер должен держать одну ссылку на все время работы (оформить в виде сервиса) (это догоро, но очень просто) или активация и деактивация (дешево и сердито с сохранением состояния).


Не думаю что так получается. первый скрипт запускает 2й, оба выводят MsgBox на котором и висят. 1й скрипт после нажатия на MsgBox'e генерит сообщение и опять идет на MsgBox (вижу и MsgBox и событие в первом скрипте). Во втором — только MsgBox.

Так работает Singleton в Dll вариант №1 (RSDN). Попробовал еще Singleton в Exe с фабрикой от MS (alternative...) — сообщения приходят в оба скрипта, но сообщения не приходят в html странице:

<html>
<body>
<body id=pagebody>
<script language="javascript">
function fnOnLoad ()
{
    alert ("Loaded");
    IEI.MakeEvent (42);
    alert ("The End");
}
</SCRIPT>

<script for="IEI" event="UsedElement(ss1)" language="JavaScript">
    alert("html. UsedElement("+ss1+")");
</script>
<body onLoad=fnOnLoad();>
<OBJECT id=IEI classid="clsid:E1F41D29-2AF1-4DE6-A9EE-E6A642DD2F2D"</OBJECT>
</body>
</html>

При том, что в скрипты сообщения приходят...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.