Форум: "Потрепаться";
Текущий архив: 2002.05.13;
Скачать: [xml.tar.bz2];
ВнизРазомнем слегка мозги ? Найти похожие ветки
← →
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;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.004 c