Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.05.13;
Скачать: CL | DM;

Вниз

Разомнем слегка мозги ?   Найти похожие ветки 

 
Digitman ©   (2002-04-04 08:47) [0]

Исх.данные :

1. Имеется некая Delphi-designed DLL L, экспортирующая некую процедуру P.

2. В теле процедуры P создается экз-р некоего доп.потока Т, класс которого явл-ся наследником стандартного класс TThread.

3. В переопределенной процедуре объкта-потока Execute() по всем правилам работы с non-thread-safe VCL-объектами (т.е. - в контексте метода Synchronize) вызывается конструктор некоей формы F, св-во Visible которой по-умолчанию = True.

4. Некое хост-приложение A импортирует проц-ру P из библ-ки L таким образом, что загрузка L и вызов P осуществляется <k>динамически</k> в контексте некоего доп.потока хост-процесса приложения A.

Целевая задача :

Не тестируя весь этот механизм "живьем", ответить на вопросы :

1. Все ли здесь корректно ?
2. Если не корректно, то почему и как это проявится при работе такого механизма "вживую" ?


 
Виктор Щербаков ©   (2002-04-04 09:07) [1]

Не тестируя очень сложно ответить, но может быть проблема в перерегистрации класса ThreadWindowClass с новым (для dll) значением HInstance?


 
Digitman ©   (2002-04-04 10:29) [2]

>Виктор Щербаков
Да нет, здесь-то как раз все в порядке : предположим, что кроме как библ-кой L класс окна ThreadWindowClass никем более не используется - в дан.момент в системе не работает ни один процесс, использующий VCL.



 
Andrey ©   (2002-04-04 11:38) [3]

Возможно метод Synchronize должен синхронизироваться с основным потоком приложения, а не с дополнительным?


 
Виктор Щербаков ©   (2002-04-04 11:43) [4]

Andrey © (04.04.02 11:38)
???
Поясни пожалуйста.
Ведь метод, передаваемый в параметре Synchronize, выполняется в контексте основного потока приложения, что достигается отправлением сообщения в окно ThreadWindow.


 
Andrey ©   (2002-04-04 11:57) [5]

>Виктор Щербаков
Да, промахнулся я. Но меня ввела в заблуждение фраза
"загрузка L и вызов P осуществляется динамически в контексте некоего доп.потока хост-процесса приложения A"

В help-е я вычита:
Synchronize causes the call specified by Method to be executed using the main VCL thread

Так-что промахнулся конкретно.


 
Виктор Щербаков ©   (2002-04-04 12:54) [6]

Я всё же не удержался и воспроизвел ситуацию.
Такое ощущение, что сообщение CM_EXECPROC, отправляемое в результате вызова Synchronize, отправляется "не туда", т.е. хэндл не соответствует тому, что я вижу в WinSight.
Почему так происходит?


 
Andrey ©   (2002-04-04 13:06) [7]

И всетаки я непонимаю каким образом Dll-ка получает значение переменной ThreadWindow, ведь (дальше идут только мои домыслы) при загрузке Dll-ки (в uses которой включен Classes) создается и новая переменная ThreadWindow которой (вот в том что я пишу дальше совсем неуверен) присваивается значение вызвавшего Dll-ку потока. Таким образом строка:

procedure TThread.Synchronize(Method: TThreadMethod);
begin
FSynchronizeException := nil;
FMethod := Method;
SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self));
if Assigned(FSynchronizeException) then raise FSynchronizeException;
end;

вызванная в потоке Dll-ки обратится к дополнительному потоку хост-процесса, как к основному.

P.S. Я наверное где-то неправ, но где? Укажите пожалуста.


 
Digitman ©   (2002-04-04 13:27) [8]

>Виктор Щербаков
Э-э-э, так нечестно - "воспроизводить ситуацию" !)))
Ну да - ладно, востпроизвел так воспроизвел ...
Ну и ? Что же все-таки происходит неожиданное ?) Или все происходит так, как ожидалось ?)

>Andrey
Коль уж "залез" в исх.текст модуля, где декларирован TThread - изучи внимательно все обращения кода модуля к идент-ру ThreadWindow, это должно многое прояснить.


 
Виктор Щербаков ©   (2002-04-04 13:46) [9]

Очевидно в dll, ThreadWindow будет создано в контексте дополнительного потока Host-процесса. В результате, когда в это окно придет сообщение CM_EXECPROC, метод VCL будет выполнен в контексте дополнительного потока Host-процесса.


 
Digitman ©   (2002-04-04 14:04) [10]

>Виктор Щербаков
Версия-то, конечно, правильная).... но ...

Ты код еще не уничтожил ? Переопредели F.WndProc() и установи в ее теле проверку
if GetCurrentThreadId = MainThreadId then ...

Результаты проверки "убьют тебя наповал")


 
Andrey ©   (2002-04-04 14:09) [11]

>Виктор Щербаков
Это же я и сказал в посте Andrey © (04.04.02 13:06)
только более расплывчато и меенее уверено, а меня изучать VCL отослали :)

И даже при конструкции которая находится в процедуре:
procedure AddThread;
begin
EnterCriticalSection(ThreadLock);
try
if ThreadCount = 0 then
ThreadWindow := AllocateWindow;
Inc(ThreadCount);
finally
LeaveCriticalSection(ThreadLock);
end;
end;

переменная ThreadCount как и переменная ThreadWindow будут загружены в двух экземплярах, в хост-процессе и в DLL-ке. И при вызове этой процедуры в DLL-ке, при создании прцесса, он и будет обьявлен основным, следовательно все Synchronize этого процесса с ним и будут синхронизироваться.


 
Digitman ©   (2002-04-04 14:45) [12]

>Andrey
По условиям задачи не сказано, что хост-приложение использует VCL. Например, хост-приложение создано в среде MS VC. Что на это скажешь ?


 
Andrey ©   (2002-04-04 15:09) [13]

Скажу что с MS VC незнаком. НО, в данном конкретном случае это неимеет никакого значения.
Ведь "Имеется некая Delphi-designed DLL", а мы знаем механизм при помощи которого созтается любой наследник TThead в Delphi. Этот механизм в свою очередь предусматривает, что любой наследник TThead который первым иниациализируется в DLL-ке становится для этой DLL-ки основным (ThreadWindow). Правда есть один вариант этого избежать (мной не проверенный и не безопасный): при инициализации DLL-ки (до создания любого наследника TThead) передать в специально предназначеную функцию значения переменных ThreadWindow(указывающюю на основной поток приложения) и ThreadCount(>0), а эта функция должна установить эти переменные локально (в DLL-ке).

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


 
Digitman ©   (2002-04-04 15:37) [14]

>Andrey
Бесспорно прав ты пока только в одном - каждый программный модуль, использующий VCL (будь то DLL, EXE или еще что-то), при загрузке получает свой экз-р сег-та данных, содержащих в т.ч. данные VCL.


 
Виктор Щербаков ©   (2002-04-04 16:01) [15]


> Ты код еще не уничтожил ? Переопредели F.WndProc() и установи
> в ее теле проверку
> if GetCurrentThreadId = MainThreadId then ...
>
> Результаты проверки "убьют тебя наповал")

А почему меня должны были "убить" результаты?
Конечно условие выполняется, но значение MainThreadId в dll не соответствует идентификатору основного потока host-процесса.
Ведь загрузка dll по условию должна выполнятся в доп. потоке. Очевидно, переменной MainThreadId и присваивается идентификатор доп. потока.


 
Digitman ©   (2002-04-04 17:11) [16]

>Виктор Щербаков
Все верно) Это была провокация)
Так, какой вывод-то следует из всего этого ? Резюме ? Для всех, кто наблюдал за нами ...


 
Andrey ©   (2002-04-04 17:23) [17]

>Digitman
Учиться, учиться, учиться... :)


 
Digitman ©   (2002-04-04 17:54) [18]

а вывод простой : реализация механизма управления синхронизацией в классе TThread далеко не универсальна (по кр. мере - вплоть до Д5), и при реализации подобных задач всегда следует иметь ввиду потенциальную возможность возникновения такой вот ситуации



Страницы: 1 вся ветка

Текущий архив: 2002.05.13;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.012 c
1-39752
Феликс
2002-04-27 22:44
2002.05.13
Как сделать, чтобы у определенной строки в Listbox был свой цвет.


4-39908
wed
2002-03-11 18:49
2002.05.13
как за свой компонент перетащить форму


6-39822
AlexRush
2002-02-28 18:14
2002.05.13
WinSock2 API - чтение данных из сокета


14-39856
Desdechado
2002-04-03 12:57
2002.05.13
тест


1-39766
AndreyS
2002-04-28 11:22
2002.05.13
Как принудительно сделать рефреш окна.