Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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
1-16231
ikivio
2004-01-26 16:25
2004.02.06
SetWindowsHookEx


1-16408
Antonyo
2004-01-21 20:03
2004.02.06
Про серверы автоматизации


14-16626
HoH
2004-01-14 20:25
2004.02.06
сайт


3-16096
HakoLamer
2004-01-10 22:27
2004.02.06
Query


14-16589
syte_ser78
2004-01-15 15:11
2004.02.06
Удаление файла досовскими командами





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский