Здравствуйте, Иван Андреев, Вы писали:
ИА>Статья:
ИА>Авторы:
ИА> Иван Андреев
Отличная статья! Содержащийся в ней материал почти что полностью исчерпывает тему. Я говорю "почти" потому, что проблема маршаллинга так и осталась не решенной в случае использования 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 корректно осуществляется маршаллинг и обработка исключительных ситуаций.