Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Потрепаться";
Текущий архив: 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
4-39882
chernoruk
2002-02-24 22:14
2002.05.13
Проблемы с EnumWindows


3-39677
Socrat
2002-04-16 09:03
2002.05.13
Помогите отучить ADO сжирать память !


6-39818
Olfi
2002-02-25 18:24
2002.05.13
Как проверить существование e-maila?


3-39649
rvs
2002-04-17 11:38
2002.05.13
Query в Query


3-39654
Елена
2002-04-05 10:56
2002.05.13
Delphi и FoxPro-таблицы





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский