Форум: "Основная";
Текущий архив: 2004.02.06;
Скачать: [xml.tar.bz2];
ВнизПотоковые модели и COM Найти похожие ветки
← →
Тимохов (2004-01-23 16:32) [0]Уважаемые мастера Дельфи, имеющие опыт в работе с COM.
Несмотря на то, что давно использую COM в своей работе, решил тут лучше изучить загадоченые (для меня) правила работы с потоками в COM.
Начал с http://podgoretsky.com/ftp/Docs/Delphi/DX/COMmodel.html
После чего почитал (правда, бегло) MSDN по этому вопросу.
Беглось вызвана базовым непониманием некоторых вопросов, некоторые из которых я приведу ниже.
Сразу скажу, что данная тема интересует меня только с точки зрения разработки клиентского приложения и использования inproc сервера с моделью Apartment. В дальнейшем, обязательно, изучу другие потоковые модели.
Заранее благодарен за ответы.
Вопрос 1. Есть следующий код.
// thread
type
TMyThread = class(TThread)
procedure Execute; override;
end;
procedure TMyThread.Execute();
begin
...
end;
// main programm
procedure TForm1.Button1OnClick(...);
var
t: TMyThread;
begin
t := TMyThread.Create(false);
end;
Скажите, пожалуйста, сколько в такой программе существует STA: два (в одном главный поток, в другом поток TMyThread) или один (содержащий оба потока)?
Остальные вопросы. Задам в зависимости от ответа на первый.
← →
Digitman (2004-01-23 16:38) [1]
> STA
переведи)..
← →
Тимохов (2004-01-23 16:39) [2]STA
single-threa ted apartment
или
single-threa ded apartment
← →
Opuhshii (2004-01-23 16:40) [3]в такой программе STA?...
нисколько,..
← →
Тимохов (2004-01-23 16:42) [4]
> в такой программе STA?...
> нисколько,..
Уверен?
CoInitialize в system вызывается (InitProc).
Модуль ComObj подключен (виноват, не написал ранее).
← →
Digitman (2004-01-23 16:44) [5]кем ? тобой в ЭТОМ потоке не вызывается точно ... не видно это из твоего кода
← →
Тимохов (2004-01-23 16:44) [6]Digitman © (23.01.04 16:44) [5]
См. [4].
Разве это не гарантирует вызова CoInitialize, который, насколько я понимаю, и делает STA.
← →
Digitman (2004-01-23 16:48) [7]нет, не гарантирует
автоматом его никто за тебя делать не будет
автоматом его вызывает лишь Борланд для осн.код.потока при использовании соотв.модулей VCL
для прочих код.потоков это будет на твоей совести
← →
Тимохов (2004-01-23 16:53) [8]Digitman © (23.01.04 16:48) [7]
Т.е. я так понимаю, что:
1. основной поток у меня в STA (т.к. вызвался InitProc, переопределенный в ComObj на вызов CoInitialize).
2. поток TMyThread вообще нигде, т.е. не в STA.
Правильно?
← →
Digitman (2004-01-23 17:00) [9]думаю, что CoInitizlize() не имеет непоср, отношения к механизму thread apartment в принципе
← →
Тимохов (2004-01-23 17:02) [10]
> думаю, что CoInitizlize() не имеет непоср, отношения к
> механизму thread apartment в принципе
Врядли, т.к. в CoInitializeEx явно задается поточкая модель.
← →
Digitman (2004-01-23 17:04) [11]где ? покажи ...
ссылка на док-цию ?
← →
Тимохов (2004-01-23 17:05) [12]Digitman © (23.01.04 17:04) [11]
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/cmf_a2c_5iyg.asp
← →
Digitman (2004-01-23 17:16) [13]ясно.
а далее, в соотв-вии с док-том, все зависит от Threading Model того объекта, к которому будут осуществляться обращения из данногго и/или иного код.потока
← →
Тимохов (2004-01-23 17:33) [14]
> а далее, в соотв-вии с док-том, все зависит от Threading
> Model того объекта, к которому будут осуществляться обращения
> из данногго и/или иного код.потока
Я вроде понял, что не совсем так.
Важна комбинация модели сервера + модель клиента + типа сервера (inproc или внешний).
Темный тут все-таки лес.
Поясню, почему возникла вообще потребность в этом разобраться.
Есть проект. В главном потоке создается AdoDb.Connection (через имортированную библиотеку типов). Есть поток, который юзает этот conntion без всякого маршалинга, чтобы раз в 10 мин обращаться к серверу. Я не устанавливаю модель потоков для клента (т.е. она соглавно описанию OnInitialize равна apartment). AdoDb имет потоковую модель apartment (согласно реестру).
Все прекрасно работает не первый год. Кто-то мне сказал, что так делать нельзя. Полез в документацию, и прочел, что к com объекту, созданному в одном STA, можно обращаться из другого STA только через маршалинг. Из того же STA можно без маршалинга. При том, если этого не делать, то я обязательно должен получить ошибку. Но я это делаю, и все работает. Т.е. получается, что главнй поток и дополнительный в одном STA.
Вот такая логика.
Но. В этом случае я совершенно не понимаю как перевести следующую фразу из MSDN "Single-threaded Apartments—Single-threaded apartments consist of exactly one thread, ". У меня потока то два :(((
ЗЫ: ясно что здесь без АП не разберешься.
← →
Бином Ньютоныч (2004-01-23 18:15) [15]1)CoInitializeEx.
Эта функция инициирует для вызвавшего ее потока подсистему COM. В том числе она определяет, в какой апартамент будет включен данный поток. Если заявлен STA, то будет создан новый апартамент, так как в STA может жить только один поток. MTA в приложении может быть только один, поэтому все потоки, запросившие эту модель, будут выполняться в одном апартаменте.
2)Зачем апартаментные модели объектам.
Апартаментная модель существует для того, чтобы подсистема COM могла оказать помощь программисту в обепечении безопасности вызовов методов одного объекта из разных потоков. Если объект зарегистрирован с моделью MTA, то это значит, что его автор позаботился об этой безопасности и помощи от COM не требуется. Если объект заявлен с моделью STA, то вызывать его методы из разных потоков одновременно небезопасно и вызовы нужно сериализовать. Такой взгляд не охватывает все нюансы, но для начала сойдет.
3)Передача интерфейсов между апартаментами.
СОМ МОЖЕТ помочь программисту в сериализации вызовов, но об этом нужно ее попросить. Эта просьба выражается в использовании механизма маршаллинга. Если просто передать ссылку на интерфейс из одного апартамента в другой, то СОМ не будет вмешиваться, это чисто твоя ответственность. И это вполне может оказаться безопасным и не привести ни к каким ошибкам, если, например, не работать с одним интерфейсом сразу в нескольких потоках. В твоем случае видимо так и происходит. Но если ты попытаешься использовать это соединение в разных потоках, то наверняка получишь ошибки из-за одновременного обращения из разных потоков к внутренним данным объекта, реализующего интерфейс, или к каким-то неразделяемым ресурсам, которые этот объект импользует.
← →
Тимохов (2004-01-23 18:22) [16]Бином Ньютоныч (23.01.04 18:15) [15]
> СОМ МОЖЕТ помочь программисту в сериализации вызовов, но
> об этом нужно ее попросить. Эта просьба выражается в использовании
> механизма маршаллинга. Если просто передать ссылку на интерфейс
> из одного апартамента в другой, то СОМ не будет вмешиваться,
> это чисто твоя ответственность. И это вполне может оказаться
> безопасным и не привести ни к каким ошибкам, если, например,
> не работать с одним интерфейсом сразу в нескольких потоках.
> В твоем случае видимо так и происходит. Но если ты попытаешься
> использовать это соединение в разных потоках, то наверняка
> получишь ошибки из-за одновременного обращения из разных
> потоков к внутренним данным объекта, реализующего интерфейс,
> или к каким-то неразделяемым ресурсам, которые этот объект
> импользует.
Огромное спасибо, что не пожалели времени на такой ответ :)))
Вопросы-уточнения.
По поводу пункта 1)
Я не понимаю, в каком аппартменте находится подчиненный поток (я не вызываю явно CoInitialize него)?
По поводу пункта 3)
Я работаю с одним интерфейсом в несокольких потоках. Но!
У меня обращение к connection защищено критической секцией.
Наверное, по этому и не происходит ничего срашного. Если критическую секцию убрать, то может быть кырдык. Правильно я понимаю?
← →
Ломброзо (2004-01-23 18:34) [17]
> У меня обращение к connection защищено критической секцией
Угу, ничего страшного. Но изобилие критических секций сводит на нет все преимущества MTA.
← →
Тимохов (2004-01-23 18:41) [18]Во, теперь MTA всплыло :(((
Все-таки не могу добиться понимания, что такое аппартмент вообще.
Насколько я понимаю, MTA это НЕ синоним многопоточное приложение. STA, соответственно, не синоним однопоточного.
Итак, вопрос остатется: сколько в приведенном примере клиентского приложения аппартменов (при условии того, что SomeComObject это внутренний apparment сервер)?
// thread
type
TMyThread = class(TThread)
procedure Execute; override;
end;
procedure TMyThread.Execute();
begin
...
o.SomeMethod;
...
end;
// main programm
uses
ComObj;
var
o: ISomeComObject;
procedure TForm1.Button1OnClick(...);
var
t: TMyThread;
begin
o := CreateComObject(...);
t := TMyThread.Create(false);
end;
← →
Бином Ньютоныч (2004-01-23 18:42) [19]>Я не понимаю, в каком аппартменте находится подчиненный поток (я не вызываю явно CoInitialize него)?
Ни в каком. Подсистема COM для него просто не проинициировна и если ты попытаешься обратиться к ее сервисам, то сразу получишь отлуп. Это относится, например, к механизму маршалинга, защиты, канальным хукам и тому подобным вкусностям:)
← →
Тимохов (2004-01-23 18:45) [20]
> Ни в каком. Подсистема COM для него просто не проинициировна
> и если ты попытаешься обратиться к ее сервисам, то сразу
> получишь отлуп. Это относится, например, к механизму маршалинга,
> защиты, канальным хукам и тому подобным вкусностям:)
То что дополнительный поток не относится ни к какому аппартменту, я понял. Спасибо.
А то, что у меня все работает объяснимо только критическими секциями при обращении к объекту, созданному в основном потоке. Правильно?
← →
Ломброзо (2004-01-23 18:49) [21]Здесь - один, главный (если включен ComObj). Под connection у тебя ADOConnection разумеется? если STA, то это гарантия того, что у тебя этот указатель на этот интерфейс будут маршалиться в другой апартмент. Поток TMyThread же у тебя CoInitialize не вызывал, потому имхо обломится.
← →
Тимохов (2004-01-23 18:51) [22]
> Поток TMyThread же у тебя CoInitialize не вызывал, потому
> имхо обломится.
Вот! В этом и корень вопроса. Поток работает. И работает хорошо - несмотря на активную эксплуатацию в течении 3 лет, ни разу не было проблем.
Вот за что я не люблю COM - все прочел, все понял, а работает не так как написано: либо не работает, когда должно, либо работает, когда не должно.
:((((
← →
Ломброзо (2004-01-23 18:55) [23]А скажи пожалуйста, с чем ты действительно работаешь? с ADOInt._Connection или TADOConnection?
← →
Тимохов (2004-01-23 18:57) [24]fAdoMainCnn := ADODB.CoConnection.Create, где ADODB модуль, созданный дельфи при импорте библиотеки типов Microsort ADODB ...
← →
Ломброзо (2004-01-23 19:06) [25]Сдаётся мне, что всё дело в том, что ты ведь включаешь ADODB_TLB.pas в модуле потока, а этот модуль включает в себя ComObj. Иначе бы ты получил эксепшн "Не был произведён вызов CoInitialize".
← →
Бином Ньютоныч (2004-01-23 19:06) [26]>Тимохов © (23.01.04 18:41) [18]
Апартамент - это абстракция, некоторый набор взаимосвязанных правил взаимодействия объектов. Допустим у тебя есть объект в DLL с моделью STA. Если ты попытаешься создать такой объект посредством стандартных механизмов COM из потока в STA, то этот объект будет создан в этом вызывающем потоке. То бишь метод CreateInstance его фабрики будет вызван в контексте этого потока. Если же создавать из потока в MTA, то СОМ запустит новый поток, проинициирует для него STA, и в нем произведет вызов CreateInstance. Это и есть применение правил межапартаментного взаимодействия. Но если ты сам получишь указатель на IClassFactory или любой другой интерфейс объекта класса, и просто вызовешь метод создания объекта, то СОМ не сможет вмешаться и объект будет создан в контексте того потока, откуда ты захотел. То же самое при передаче интерфейса между апартаментами. Если использовать маршалинг, то при демаршалинге СОМ определит, что импорт производится в иной апартамент, нежели апартамент-экспортер. В этом случае в импортере будет создан прокси, и его интерфейс вернет Counmarshalinterface. А если, как в примере, просто передать ссылку, то СОМ не вмешается. Это будет обыкновенное присваивание одной переменной значения другой. По сути ничем не отличается от такого:
var
a, b: integer;
...
b:=a;
Никакой разницы.
> (при условии того, что SomeComObject это внутренний apparment сервер)?
Вероятно, это оговорка. Объект и апартамент - совершенно разные понятия, смотри выше.
← →
Ломброзо (2004-01-23 19:08) [27]попробуй создать _Connection через CoCreateInstance и обратиться к нему в главном потоке (в каком-нить ButtonClick) без предварительного вызова CoInitialize.
← →
Ломброзо (2004-01-23 19:10) [28]не просто создать, а вызвать какой-нить метод
← →
Тимохов (2004-01-23 19:20) [29]
> Ломброзо © (23.01.04 19:06) [25]
> Сдаётся мне, что всё дело в том, что ты ведь включаешь ADODB_TLB.pas
> в модуле потока, а этот модуль включает в себя ComObj. Иначе
> бы ты получил эксепшн "Не был произведён вызов CoInitialize".
Здесь, я думаю, что Вы не совсем правы: если в модуль потока включен ComObj, это не значит, что для потока вызван метод OnInitialize. Он вызывается только если это сделать явно в Execute.
Бином Ньютоныч (23.01.04 19:06) [26]
Еще раз спасибо.
> > (при условии того, что SomeComObject это внутренний apparment
> сервер)?
> Вероятно, это оговорка. Объект и апартамент - совершенно
> разные понятия, смотри выше.
Имелось в виду, это inproc server с моделью appartment, которая прописана в реестре.
Не буду Вас утруждать более вопросами, кроме одного - ответ на него даст мне пищу для размышлений.
Будет ли в приведенном ниже примере создано два STA аппартамента для главного потока и для подчиненного:
// thread
type
TMyThread = class(TThread)
procedure Execute; override;
end;
procedure TMyThread.Execute();
begin
CoInitialize(nil);
... // do something
CoUnInitialize();
end;
// main programm
uses
ComObj;
procedure TForm1.Button1OnClick(...);
var
t: TMyThread;
begin
t := TMyThread.Create(false);
end;
Понятно, что, наверное, ответ на данный вопрос я уже мог получить из ответов в данной ветке. Просто хочу еще раз услышать короткий ответ и продолжить изучение этой темы, отталкиваясь от полученных знаний :)))
Заранее спасибо.
← →
Бином Ньютоныч (2004-01-23 19:30) [30]>Будет ли в приведенном ниже примере создано два STA >аппартамента для главного потока и для подчиненного
Несомненно:) Хотя, конечно, корректнее все же проверять результат вызова CoInitialize..ну так, от греха подальше:)
← →
Тимохов (2004-01-23 19:30) [31]Бином Ньютоныч (23.01.04 19:30) [30]
Большое спасибо за ответы.
Буду дальше изучать...
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2004.02.06;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.034 c