Есть COM server, состоящий из нескольких потоков
Есть отдельный класс, реализующий поддержку Events ( через IConnectionPoint ),
объявленные с использованием DECLARE_CLASSFACTORY_SINGLETON
Клиент Создает объект этого класса и подсоединяется к Events
Сервер, чтобы послать сообщение клиенту, создает объект и вызывает что-то типа Fire_ляляля
Так вот, сообщения доходят до клиента, только в случае, если объект с Events создавался в том же потоке, что и server, в других потоках происходит exception при вызове Invoke внутри метода Fire_ляляля
Вопрос : ПОЧЕМУ?
Насколько я понимаю, необходимо копать в направлении маршаллинга.
Re: Проблема вызовом Events в многопоточном объекте
Здравствуйте 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, Вы писали:
H>Так вот, сообщения доходят до клиента, только в случае, если объект с Events создавался в том же потоке, что и server, в других потоках происходит exception при вызове Invoke внутри метода Fire_ляляля
Вроде это уже здесь обсуждалось (я такой вопрос задавал
В простейшем случае делаешь CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream для конкретного интерфейса. Но это если у тебя один такой особенный интерфейс и ты можешь позволить уделить ему особое внимание. В более общем случае — перекрываешь ATL-ный Advise (реализация здесь пробегала), но мне оно тоже не очень понравилось.
Я для своей задачи останавился на варианте с PostThreadMessage, т.е. когда нужно кинуть евент из другого потока — посылается соответсвующее сообщение в потоко сервера и там уже обрабатвается.
Как все запущенно...
Re[2]: Проблема вызовом Events в многопоточном объекте
Здравствуйте Vladik, Вы писали:
V>Вроде это уже здесь обсуждалось (я такой вопрос задавал V>В простейшем случае делаешь CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream для конкретного интерфейса. Но это если у тебя один такой особенный интерфейс и ты можешь позволить уделить ему особое внимание. В более общем случае — перекрываешь ATL-ный Advise (реализация здесь пробегала), но мне оно тоже не очень понравилось. V>Я для своей задачи останавился на варианте с PostThreadMessage, т.е. когда нужно кинуть евент из другого потока — посылается соответсвующее сообщение в потоко сервера и там уже обрабатвается.
Насколько я понимаю, эти действия нужно делать при подключении к уведомлениям?
Единственное, что непонятно — если мой компонент (реализующий IConnectionPoint) оформлен в виде DLL, то как имеено он сможет использовать указанный механизм? Ведь для этого он должен, как минимум завести собственный поток с который будет следить за определенными сообщениями (добавления/удаления sink-объектов, точнее их proxy, созданных через CoGetInterfaceAndReleaseStream ) и генерации вызовов (с proxy sink-объекта ведь должен общаться тот же поток, который вызвал CoGetInterfaceAndReleaseStream?).
А при большом числе компонент это становиться накладно... (вопрос о совместном использовании потока для обслуживания proxy-sink-объектов не будем рассматривать)
Или все гораздо проще (хуже?)
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[3]: Проблема вызовом Events в многопоточном объекте
Здравствуйте Коваленко Дмитрий, Вы писали:
КД>Насколько я понимаю, эти действия нужно делать при подключении к уведомлениям?
Нет, наверное я неправильно понял первоначальный вопрос. Эти действия делаются при желании на сервере сделать FireEvent (то бишь послать уведомление клиенту) из потока, отличного от того, в котором клиентом был сделан Advise.
КД>Единственное, что непонятно — если мой компонент (реализующий IConnectionPoint) оформлен в виде DLL, то как имеено он сможет использовать указанный механизм?
Клиент ничего не должен. Это же сервер у тебя многопоточный 0 пусть он и разбирается. Клиент после Advise только ловит события обычным способом.
[...] КД>Или все гораздо проще (хуже?)
Или я чего-то не понял
Как все запущенно...
Re[4]: Проблема вызовом Events в многопоточном объекте
Здравствуйте Vladik, Вы писали:
V>Здравствуйте Коваленко Дмитрий, Вы писали:
КД>>Насколько я понимаю, эти действия нужно делать при подключении к уведомлениям?
V>Нет, наверное я неправильно понял первоначальный вопрос. Эти действия делаются при желании на сервере сделать FireEvent (то бишь послать уведомление клиенту) из потока, отличного от того, в котором клиентом был сделан Advise.
То есть сервер при Advise однозначно должен создать proxy переданного sink объекта (должен же он как то запомнить из какого потока к нему подключились — пусть это сделает proxy).
этот proxy, насколько я понимаю, может использоваться только в том потоке, который вызвал CoGetInterfaceAndReleaseStream. То есть если клиенты работают в разных потоках, proxy нужно создавать в другом (своем собственном) потоке.
поток который вызвал CoGetInterfaceAndReleaseStream, однозначно должен контролироваться компонентом (то бишь сервером), поскольку именно из этого потока должна происходить генерация уведомлений (то есть обход и вызов элементов списка proxy sink-объектов)
если компонент (или сервер) грузиться в виде DLL в инородный процесс, то для выполнения вышеуказанных задач он должен иметь свой персональный поток. Остальные, в общем случае, ему не подвластны. То есть созданные proxy не могут принадлежать не одному из них. Почему? Я так полагаю (надеюсь, что правильно) что
с proxy можно работать (повторяюсь?) только в том потоке, в котором он создан
proxy автоматически разрушиться системой, когда завершиться поток
Если сервер — exe, то он же и контролирует свои потоки. DLL увы полностью зависит от прихотей того кто её загрузил — насколько я копал, она даже не в состоянии (законным способом?) выяснить в какой threaded-model её загрузили. Типа системе виднее. Короче песец .
Вот и остается как заводить свои потоки, которые при большом числе экземпляров приведут к другой ....
Да, забыл сказать, это все мои мысли не подтвержденные практикой (не припирало еще пока). Так что... только для сведения
КД>>Единственное, что непонятно — если мой компонент (реализующий IConnectionPoint) оформлен в виде DLL, то как имеено он сможет использовать указанный механизм?
V>Клиент ничего не должен. Это же сервер у тебя многопоточный 0 пусть он и разбирается. Клиент после Advise только ловит события обычным способом.
Надо разобраться, что мы понимаем под словом сервер.
КД>>Или все гораздо проще (хуже?)
V>Или я чего-то не понял
Точно — кажется, мы говорим о разных вещах.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[5]: Проблема вызовом Events в многопоточном объекте
Здравствуйте Коваленко Дмитрий, Вы писали:
КД>сервер при 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 в многопоточном объекте
Здравствуйте VladD2, Вы писали:
VD>Здравствуйте Коваленко Дмитрий, Вы писали:
КД>>сервер при Advise однозначно должен создать proxy переданного sink объекта (должен же он как то запомнить из какого потока к нему подключились — пусть это сделает proxy).
VD>Во сформулировал! Ты думаешь тебе с клиента что приезжает? Именно прокси и приезжает. Только вот одна загвоздка. Прокси (любая даже от MTA-объекта) жостко привязана к потоку. И вызвывать ее нужно из этого потока. Если нужно вызвать из другого, то маршаль вручную (или GIT-ом).
Вот именно — я только думаю . О чем и предупредил.
Если приезжаем именно прокси, то проблем вообще нет. И я тогда не понял зачем вся эта тема затеялась. А проверить что именно proxy — можно?
Мысль, что нужно создать proxy, возникла как раз из предположения, что будет передан сам объект. Вообще говоря, я так и не врубился — сервер оформлен в виде DLL или EXE?
Если в виде DLL, то proxy будут создаваться если объект сервера передается клиентам (живущим в потоках того же сервера) через тот же ручной маршалинг. Тогда да (ты прав) в поток сервера будет передан proxy sink'a. Внутри пусть, мать его так, сам обеспечиват корректное использование этого proxy-sink объекта.
Короче, надо завязывать. Это все равно что советывать как правильно делать детей
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[5]: Проблема вызовом Events в многопоточном объекте
Здравствуйте Коваленко Дмитрий, Вы писали:
КД>То есть КД>[list=1] КД>сервер при Advise однозначно должен создать proxy переданного sink объекта (должен же он как то запомнить из какого потока к нему подключились — пусть это сделает proxy).
Не уверен, что я правильно представляю, что такое "создать proxy переданного sink объекта", но звучит вполне убедительно
КД>этот proxy, насколько я понимаю, может использоваться только в том потоке, который вызвал CoGetInterfaceAndReleaseStream. То есть если клиенты работают в разных потоках, proxy нужно создавать в другом (своем собственном) потоке.
Стоп. Причем здесь клиенты в разных потоках? Серверу до лампочки в каких там потоках его клиенты. CoGetInterfaceAndReleaseStream делает сервер из _своего_ более другого потока, чтобы этот более другой поток мог что-то сделать с событийным интерфейсом (кинуть евент).
[...]
По остальным пунктам я потерял логическую нить
КД>Если сервер — exe, то он же и контролирует свои потоки. DLL увы полностью зависит от прихотей того кто её загрузил
Ну потоки свои она создавать может. Не могу забыть, как я боролся с интербейзом (точнее его gds32.dll), которая создавала поток и при дисконнекте впендюривала для него реалтайм приоритет... !@#$
>- насколько я копал, она даже не в состоянии (законным способом?) выяснить в какой threaded-model её загрузили. Типа системе виднее. Короче песец .
Дык, нафига ей знать я так и не понял
[...] КД>Надо разобраться, что мы понимаем под словом сервер.
Сервер это тот, кто предоставляет услуги (и, в частности, генерирует события). Есть другие мнения?
Как все запущенно...
Re[6]: Проблема вызовом Events в многопоточном объекте
Здравствуйте Vladik, Вы писали:
V>[...]
V>По остальным пунктам я потерял логическую нить
Не обращай внимание — это был поток мыслей оторванного сознания
КД>>Если сервер — exe, то он же и контролирует свои потоки. DLL увы полностью зависит от прихотей того кто её загрузил
V>Ну потоки свои она создавать может. Не могу забыть, как я боролся с интербейзом (точнее его gds32.dll), которая создавала поток и при дисконнекте впендюривала для него реалтайм приоритет... !@#$
Вот ведь...
А что за версия сервера была?
И что за задача, которой мешал поток gds32?
-- Пользователи не приняли программу. Всех пришлось уничтожить. --