Проблема вызовом Events в многопоточном объекте
От: homogenic  
Дата: 30.01.02 17:21
Оценка:
Есть COM server, состоящий из нескольких потоков
Есть отдельный класс, реализующий поддержку Events ( через IConnectionPoint ),
объявленные с использованием DECLARE_CLASSFACTORY_SINGLETON

Клиент Создает объект этого класса и подсоединяется к Events


Сервер, чтобы послать сообщение клиенту, создает объект и вызывает что-то типа Fire_ляляля


Так вот, сообщения доходят до клиента, только в случае, если объект с Events создавался в том же потоке, что и server, в других потоках происходит exception при вызове Invoke внутри метода Fire_ляляля



Вопрос : ПОЧЕМУ?
Насколько я понимаю, необходимо копать в направлении маршаллинга.
Re: Проблема вызовом Events в многопоточном объекте
От: ioni Россия  
Дата: 30.01.02 20:01
Оценка:
Здравствуйте homogenic, Вы писали:

H>Есть COM server, состоящий из нескольких потоков

H>Есть отдельный класс, реализующий поддержку Events ( через IConnectionPoint ),
H>объявленные с использованием DECLARE_CLASSFACTORY_SINGLETON

H>Клиент Создает объект этого класса и подсоединяется к Events



H>Сервер, чтобы послать сообщение клиенту, создает объект и вызывает что-то типа Fire_ляляля



H>Так вот, сообщения доходят до клиента, только в случае, если объект с Events создавался в том же потоке, что и server, в других потоках происходит exception при вызове Invoke внутри метода Fire_ляляля




H>Вопрос : ПОЧЕМУ?

H>Насколько я понимаю, необходимо копать в направлении маршаллинга.

код в студию как ты цепляешся к евентам
модели потоков объекта клиента
Re[2]: Проблема вызовом Events в многопоточном объекте
От: homogenic  
Дата: 31.01.02 08:24
Оценка:
I>код в студию как ты цепляешся к евентам
I>модели потоков объекта клиента


в коде сервера : (подход из одной статьи с этого сайта)

CComPtr<IMyEvents> pEvent;
pEvent.CoCreateInstance(CLSID_MyEvents);
pEvent->FireOnMyEvent( dwLastError, L"" );



FireOnMyEvent вызывает Fire_OnMyEvent, сгенеренную ATL Wizard-ом


Клиент вообще написан на VB.

Подсоединяюсь через Dim WithEvents ClientEvents As MyDLLLib.MyEvents
Re: Проблема вызовом Events в многопоточном объекте
От: Vladik Россия  
Дата: 31.01.02 09:40
Оценка:
Здравствуйте homogenic, Вы писали:

H>Так вот, сообщения доходят до клиента, только в случае, если объект с Events создавался в том же потоке, что и server, в других потоках происходит exception при вызове Invoke внутри метода Fire_ляляля


Вроде это уже здесь обсуждалось (я такой вопрос задавал
В простейшем случае делаешь CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream для конкретного интерфейса. Но это если у тебя один такой особенный интерфейс и ты можешь позволить уделить ему особое внимание. В более общем случае — перекрываешь ATL-ный Advise (реализация здесь пробегала), но мне оно тоже не очень понравилось.
Я для своей задачи останавился на варианте с PostThreadMessage, т.е. когда нужно кинуть евент из другого потока — посылается соответсвующее сообщение в потоко сервера и там уже обрабатвается.
Как все запущенно...
Re[2]: Проблема вызовом Events в многопоточном объекте
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 01.02.02 07:06
Оценка:
Здравствуйте Vladik, Вы писали:

V>Вроде это уже здесь обсуждалось (я такой вопрос задавал

V>В простейшем случае делаешь CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream для конкретного интерфейса. Но это если у тебя один такой особенный интерфейс и ты можешь позволить уделить ему особое внимание. В более общем случае — перекрываешь ATL-ный Advise (реализация здесь пробегала), но мне оно тоже не очень понравилось.
V>Я для своей задачи останавился на варианте с PostThreadMessage, т.е. когда нужно кинуть евент из другого потока — посылается соответсвующее сообщение в потоко сервера и там уже обрабатвается.

Насколько я понимаю, эти действия нужно делать при подключении к уведомлениям?

Единственное, что непонятно — если мой компонент (реализующий IConnectionPoint) оформлен в виде DLL, то как имеено он сможет использовать указанный механизм? Ведь для этого он должен, как минимум завести собственный поток с который будет следить за определенными сообщениями (добавления/удаления sink-объектов, точнее их proxy, созданных через CoGetInterfaceAndReleaseStream ) и генерации вызовов (с proxy sink-объекта ведь должен общаться тот же поток, который вызвал CoGetInterfaceAndReleaseStream?).

А при большом числе компонент это становиться накладно... (вопрос о совместном использовании потока для обслуживания proxy-sink-объектов не будем рассматривать)

Или все гораздо проще (хуже?)
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[3]: Проблема вызовом Events в многопоточном объекте
От: Vladik Россия  
Дата: 01.02.02 10:46
Оценка:
Здравствуйте Коваленко Дмитрий, Вы писали:

КД>Насколько я понимаю, эти действия нужно делать при подключении к уведомлениям?


Нет, наверное я неправильно понял первоначальный вопрос. Эти действия делаются при желании на сервере сделать FireEvent (то бишь послать уведомление клиенту) из потока, отличного от того, в котором клиентом был сделан Advise.

КД>Единственное, что непонятно — если мой компонент (реализующий IConnectionPoint) оформлен в виде DLL, то как имеено он сможет использовать указанный механизм?


Клиент ничего не должен. Это же сервер у тебя многопоточный 0 пусть он и разбирается. Клиент после Advise только ловит события обычным способом.

[...]
КД>Или все гораздо проще (хуже?)

Или я чего-то не понял
Как все запущенно...
Re[4]: Проблема вызовом Events в многопоточном объекте
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 01.02.02 12:37
Оценка:
Здравствуйте Vladik, Вы писали:

V>Здравствуйте Коваленко Дмитрий, Вы писали:


КД>>Насколько я понимаю, эти действия нужно делать при подключении к уведомлениям?


V>Нет, наверное я неправильно понял первоначальный вопрос. Эти действия делаются при желании на сервере сделать FireEvent (то бишь послать уведомление клиенту) из потока, отличного от того, в котором клиентом был сделан Advise.


То есть
  1. сервер при Advise однозначно должен создать proxy переданного sink объекта (должен же он как то запомнить из какого потока к нему подключились — пусть это сделает proxy).
  2. этот proxy, насколько я понимаю, может использоваться только в том потоке, который вызвал CoGetInterfaceAndReleaseStream. То есть если клиенты работают в разных потоках, proxy нужно создавать в другом (своем собственном) потоке.
  3. поток который вызвал CoGetInterfaceAndReleaseStream, однозначно должен контролироваться компонентом (то бишь сервером), поскольку именно из этого потока должна происходить генерация уведомлений (то есть обход и вызов элементов списка proxy sink-объектов)
  4. если компонент (или сервер) грузиться в виде DLL в инородный процесс, то для выполнения вышеуказанных задач он должен иметь свой персональный поток. Остальные, в общем случае, ему не подвластны. То есть созданные proxy не могут принадлежать не одному из них. Почему? Я так полагаю (надеюсь, что правильно) что
    • с proxy можно работать (повторяюсь?) только в том потоке, в котором он создан
    • proxy автоматически разрушиться системой, когда завершиться поток
Если сервер — exe, то он же и контролирует свои потоки. DLL увы полностью зависит от прихотей того кто её загрузил — насколько я копал, она даже не в состоянии (законным способом?) выяснить в какой threaded-model её загрузили. Типа системе виднее. Короче песец .

Вот и остается как заводить свои потоки, которые при большом числе экземпляров приведут к другой ....

Да, забыл сказать, это все мои мысли не подтвержденные практикой (не припирало еще пока). Так что... только для сведения

КД>>Единственное, что непонятно — если мой компонент (реализующий IConnectionPoint) оформлен в виде DLL, то как имеено он сможет использовать указанный механизм?


V>Клиент ничего не должен. Это же сервер у тебя многопоточный 0 пусть он и разбирается. Клиент после Advise только ловит события обычным способом.


Надо разобраться, что мы понимаем под словом сервер.

КД>>Или все гораздо проще (хуже?)


V>Или я чего-то не понял


Точно — кажется, мы говорим о разных вещах.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[5]: Проблема вызовом Events в многопоточном объекте
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.02.02 21:19
Оценка:
Здравствуйте Коваленко Дмитрий, Вы писали:

КД>сервер при Advise однозначно должен создать proxy переданного sink объекта (должен же он как то запомнить из какого потока к нему подключились — пусть это сделает proxy).


Во сформулировал! Ты думаешь тебе с клиента что приезжает? Именно прокси и приезжает. Только вот одна загвоздка. Прокси (любая даже от MTA-объекта) жостко привязана к потоку. И вызвывать ее нужно из этого потока. Если нужно вызвать из другого, то маршаль вручную (или GIT-ом).

КД>этот proxy, насколько я понимаю, может использоваться только в том потоке, который вызвал CoGetInterfaceAndReleaseStream.


CoGetInterfaceAndReleaseStream — это и есть ручной маршалинг.

КД>То есть если клиенты работают в разных потоках, proxy нужно создавать в другом (своем собственном) потоке.


Да. Или как я уже говорил GIT пользовать.

КД>поток который вызвал CoGetInterfaceAndReleaseStream, однозначно должен контролироваться компонентом (то бишь сервером), поскольку именно из этого потока должна происходить генерация уведомлений (то есть обход и вызов элементов списка proxy sink-объектов)


Ничего непонятно.

КД>если компонент (или сервер) грузиться в виде DLL в инородный процесс, то для выполнения вышеуказанных задач он должен иметь свой персональный поток.


Это утверждение ошибочно. Может иметь, а может не иметь.

КД>Остальные, в общем случае, ему не подвластны. То есть созданные proxy не могут принадлежать не одному из них.


Чё?

КД>proxy автоматически разрушиться системой, когда завершиться поток


Это тоже ... Прокси разрушается когда ему релиз вызвали.

КД>Если сервер — exe, то он же и контролирует свои потоки. DLL увы полностью зависит от прихотей того кто её загрузил — насколько я копал, она даже не в состоянии (законным способом?) выяснить в какой threaded-model её загрузили. Типа системе виднее. Короче песец .


Начтем с того, что длл может создавать потоки в лучшем виде. Главное чтобы она их грахать не забывала (при релизе компонента который их создает).

Ну, а закончим тем, что я непойму чем вам всем мешает поток самого компонента? Почему из него нельзя вызвать эти события?

КД>Вот и остается как заводить свои потоки, которые при большом числе экземпляров приведут к другой ....


Ну, потоки и с малым количеством приведут к...

КД>Да, забыл сказать, это все мои мысли не подтвержденные практикой (не припирало еще пока). Так что... только для сведения


В ascDB создается работчий поток (в длл-ине) и прекрасно работает. Правда колбыков через апартаменты мы не делаем, но тому есть свои причины.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Проблема вызовом Events в многопоточном объекте
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 02.02.02 05:22
Оценка:
Здравствуйте VladD2, Вы писали:

VD>Здравствуйте Коваленко Дмитрий, Вы писали:


КД>>сервер при Advise однозначно должен создать proxy переданного sink объекта (должен же он как то запомнить из какого потока к нему подключились — пусть это сделает proxy).


VD>Во сформулировал! Ты думаешь тебе с клиента что приезжает? Именно прокси и приезжает. Только вот одна загвоздка. Прокси (любая даже от MTA-объекта) жостко привязана к потоку. И вызвывать ее нужно из этого потока. Если нужно вызвать из другого, то маршаль вручную (или GIT-ом).

Вот именно — я только думаю . О чем и предупредил.
Если приезжаем именно прокси, то проблем вообще нет. И я тогда не понял зачем вся эта тема затеялась. А проверить что именно proxy — можно?

Мысль, что нужно создать proxy, возникла как раз из предположения, что будет передан сам объект. Вообще говоря, я так и не врубился — сервер оформлен в виде DLL или EXE?

Если в виде DLL, то proxy будут создаваться если объект сервера передается клиентам (живущим в потоках того же сервера) через тот же ручной маршалинг. Тогда да (ты прав) в поток сервера будет передан proxy sink'a. Внутри пусть, мать его так, сам обеспечиват корректное использование этого proxy-sink объекта.

Короче, надо завязывать. Это все равно что советывать как правильно делать детей
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[5]: Проблема вызовом Events в многопоточном объекте
От: Vladik Россия  
Дата: 04.02.02 11:16
Оценка:
Здравствуйте Коваленко Дмитрий, Вы писали:

КД>То есть

КД>[list=1]
КД>
  • сервер при Advise однозначно должен создать proxy переданного sink объекта (должен же он как то запомнить из какого потока к нему подключились — пусть это сделает proxy).

    Не уверен, что я правильно представляю, что такое "создать proxy переданного sink объекта", но звучит вполне убедительно

    КД>
  • этот proxy, насколько я понимаю, может использоваться только в том потоке, который вызвал CoGetInterfaceAndReleaseStream. То есть если клиенты работают в разных потоках, proxy нужно создавать в другом (своем собственном) потоке.

    Стоп. Причем здесь клиенты в разных потоках? Серверу до лампочки в каких там потоках его клиенты. CoGetInterfaceAndReleaseStream делает сервер из _своего_ более другого потока, чтобы этот более другой поток мог что-то сделать с событийным интерфейсом (кинуть евент).

    [...]

    По остальным пунктам я потерял логическую нить

    КД>Если сервер — exe, то он же и контролирует свои потоки. DLL увы полностью зависит от прихотей того кто её загрузил


    Ну потоки свои она создавать может. Не могу забыть, как я боролся с интербейзом (точнее его gds32.dll), которая создавала поток и при дисконнекте впендюривала для него реалтайм приоритет... !@#$

    >- насколько я копал, она даже не в состоянии (законным способом?) выяснить в какой threaded-model её загрузили. Типа системе виднее. Короче песец .


    Дык, нафига ей знать я так и не понял

    [...]
    КД>Надо разобраться, что мы понимаем под словом сервер.

    Сервер это тот, кто предоставляет услуги (и, в частности, генерирует события). Есть другие мнения?
  • Как все запущенно...
    Re[6]: Проблема вызовом Events в многопоточном объекте
    От: Коваленко Дмитрий Россия http://www.ibprovider.com
    Дата: 04.02.02 11:27
    Оценка:
    Здравствуйте Vladik, Вы писали:

    V>[...]


    V>По остальным пунктам я потерял логическую нить


    Не обращай внимание — это был поток мыслей оторванного сознания

    КД>>Если сервер — exe, то он же и контролирует свои потоки. DLL увы полностью зависит от прихотей того кто её загрузил


    V>Ну потоки свои она создавать может. Не могу забыть, как я боролся с интербейзом (точнее его gds32.dll), которая создавала поток и при дисконнекте впендюривала для него реалтайм приоритет... !@#$


    Вот ведь...
    А что за версия сервера была?
    И что за задача, которой мешал поток gds32?
    -- Пользователи не приняли программу. Всех пришлось уничтожить. --
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.