![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
IdUDPServer в dll [D6, Win2k]
alin © (2004-03-22 08:39:00)в dll находится форма на которой лежит IdUDPServer форма создаётся при загрузке dll,
при выгрузке её из памяти приложение зависает если свойство Active UDPServera установлено в True если установлено False то выгрузка проходит нормально, попытка в событии destroy формы установить false не помогает.
Помогине кто может, что я делаю не так!
alin (2004-03-23 12:05:00) [1]Там все формы сделаны как дочернии окна Runtime моя форма после определённых действий закрывается на всегда и запускается форма чужого приложения, поэтому дальше все работают со старым приложением
а к нему подружены некоторые dll
в общем всё уже понятно и выкрутиться можно
Digitman (2004-03-23 11:34:00) [2]
> если запустить сначала свою форму то в ней можно и загрузить
> dll
ну, наверно, у "твоей" формы есть какие-то события ? Загрузка ? Выгрузка ?
Мне не оч понятно, что мешает в событии загрузки "твоей" формы грузить твою же DLL, в событии выгрузки "твоей" формы сначала вызвать эксп.ф-цию этой DLL, а следом выгрузить и саму DLL ?
alin (2004-03-23 11:21:00) [3]просто в Oracle Forms пользовательские формы запускаются в оболочке Runtime если запустить сначала свою форму то в ней можно и загрузить dll она подгружается к Runtime и выгружается при его закрытии, просто хотелось по простому, придётся как всегда ...
Digitman (2004-03-23 11:11:00) [4]
> чужим приложением
я не знаю что такое "Формы Оракла ", но ты же как-то умудряешься заставить "чужое приложение" грузить твой модуль ? ... думаю, точно так же можно заставить это приложение и вызывать любые эксп.ф-ции из твоего модуля
даже если это нельзя сделать явно и документированно (т.е. по соглашениям с "чужим приложением"), это всегда можно сделать и с помощью различногго рода трюков, например, с внедрением хука
alin (2004-03-23 10:35:00) [5]видете ли эта dll предполагалась использоваться с Oracle Forms
причём чужим приложением и когда приложение будет закрыто я не могу знать и вызвать экспортируемую функцию для прибития потоков тоже не могу
единственное событие подвласное мне это DLL_PROCESS_DETACH
Verg (2004-03-23 10:17:00) [6]
> но сам поток-то, imho, завершается штатно ! ..
При штатном завершениее, но без выгрузки, ранее загружненной библиотеки, поток именно что завершается НЕ нормально. Это я вижу.
Опять же: поставь точку остонова на messageBeep в поточной ф-ции примера.
И закрой приложение штатно, но без FreeLibrary.
Не останавливается там. Т.е. поток просто прибивается.
И это не связано с DLL или там не с DLL. Так поступает система с любым потоком процесса, если он не сделал ExitThread (не завершился нормально) до ExitProcess главного. Я так понял.
Меня смутило другое - потоки она прибивает ДО вызовов DLL_PROCESS_DETACH во все DLL-ки.
Наверно это и логично.
Ну да ладно, дело не в том.
Т.е. при использовании серверных компонентов, основанных на многопоточной схеме (а это как правило сервера с синхронными сокетами) надо опасаться работать с ними в DLLProc, особенно в DLL_PROCESS_DETACH.
Для деактивации придется експортнуть ф-цию, которая бы останавливала все серверные потоки (IdUDPServer.Active := false, в данном случае). И эту ф-цию придется вызывать каждый раз перед FreeLibrary.
Digitman (2004-03-23 10:07:00) [7]
> Verg
вот тут Игорь Шевченко на умную мысль наводит, что при выполнении ExitProcess система автоматом вызывает DisableThreadLibraryCalls для каждого выгружаемого модуля
есть ли в этом плане смысл пробовать следующее :
procedure MyDLLProc(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then
begin
DisableThreadLibraryCalls(hInstance);
frmMain1.Free;
end;
Digitman (2004-03-23 09:58:00) [8]
> Verg © (23.03.04 09:39) [17]
возможно, при штатном завершении процесса система попросту не вызывает THREAD_DETACH .. но сам поток-то, imho, завершается штатно ! .. и здесь ведь неважно, где ему скомандовали "закругляться" - в обработчике ли PROCESS_DETACH либо в ином месте ..
Verg (2004-03-23 09:39:00) [9]
> В DLLProc вызовется один раз с параметром DLL_PROCESS_DETACH
> и уже в нем того потока не будет существовать, как будь-то
> ему сделали TerminateThread.
Поэтому-то дедлока и не возникает. Это про ф-цию TerminateThread
The state of the thread object becomes signaled, releasing any other threads that had been waiting for the thread to terminate. The thread's termination status changes from STILL_ACTIVE to the value of the dwExitCode parameter.
Verg (2004-03-23 09:37:00) [10]Я про штатное ExitProcess. Именно про штатное.
В приведенном мною примере в хост-приложеннии загрузи эту библиотеку (LoadLibrary), а затем закрой хост-приложение (на крестик нажми :)).
В DLLProc вызовется один раз с параметром DLL_PROCESS_DETACH и уже в нем того потока не будет существовать, как будь-то ему сделали TerminateThread.
Digitman (2004-03-23 09:23:00) [11]
> Verg © (23.03.04 09:02) [14]
ты про какое терминирование процесса говоришь ? Штатное (ExitProcess) или аварийное (TerminateProcess) ? в первом случае д.б. тот же дедлок - процесс ведь не м.б. завершен без завершения всех его доп.код.потоков .. а во втором - конечно, PROCESS/THREAD_DETACH ожидать бессмысленно
Verg (2004-03-23 09:02:00) [12][13] Digitman © (23.03.04 08:58)
А не происходит DLL_THREAD_DETACH. Да и с чего бы? Ведь ф-цию ExitThread никто не вызывал в этом случае. Я так понимаю, что тут происходит какое-то насильственное убиение потока типа TerminateThread.
Во всяком случае очень похоже на то.
Digitman (2004-03-23 08:58:00) [13]
> Verg © (23.03.04 08:21) [12]
а попробуй при автовыгрузке (т.е. без явного FreeLibrary) "поймать" DLL_THREAD_DETACH ... и тут же посмотреть, CurrentThreadId = MainThreadId ?
Verg (2004-03-23 08:21:00) [14]Да, все так и есть.
Вот попробовал безо всяких там Indy
library DllUDP;
uses
SysUtils,
Classes,
Windows;
type
TMyThread = class( TThread )
public
procedure Execute; override;
end;
var
MyT : TMyThread;
procedure TMyThread.Execute;
begin
while not Terminated do
Sleep(1000);
messageBeep($FFFF);
end;
procedure MyDLLProc(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then
begin
if MyT <> nil then
begin
MyT.Terminate;
MyT.WaitFor;
end;
FreeAndNil(MyT);
end;
end;
begin
DLLProc := @MyDLLProc;
MyT := TMyThread.Create(false);
end.
При попытке выгрузить Dll-ку (FreeLibrary) приходит DeadLock на MyT.WaitFor.
DLLProc вызывается c DLL_PROCESS_DETACH и мы завершаем поток. Поточная ф-ция-то завершается, но его Handle не переходит в сигнальное состояние, т.к. для завершение потока необходимо вызывать DLL_THREAD_DETACH для всех DLL-ек процесса, но поток процесс уже находится в DLLProc одной из этих DLL-ек....однако
Only one thread in a process can be in a DLL initialization or detach routine at a time.
Но самое прикольное происходит при зваершении процесса, когда мы закрываем процесс, предварительно НЕ вызвав FreeLibrary....
Я пока не понимаю.... но тот поток (MyT) просто как бы "исчезает" (не объект, а его кодовый контекст) из системы, что видно в DLLProc при DLL_PROCESS_DETACH, если открыть окно Threads у отладчика. Однако его Handle установлен в сигнальное состояние.
Надо че-нить почитать....
Verg (2004-03-23 07:47:00) [15]Нельзя этого делать в DllProc. Нельзя делать UDPS.Active:=false;
На DLL_PROCESS_DETACH происходит завершение кодового потока UDP сервера, для чего системе надо вызвать DLL_THREAD_DETACH этой же самой DLL-ки. "Патовая" ситуация
DLL_PROCESS_DETACH ожидает, когда завершится поток, а поток завершится не может, так как нужно вызвать DLL_THREAD_DETACH, что произойдет только после завершения DLL_PROCESS_DETACH.
Спецы по WINAPI могут объяснить это более внятно, но суть в том, что в DllProc завершать потоки и ожидать их завершения нельзя - приводит к DeadLock.
alin (2004-03-23 05:20:00) [16]просто зависает без всякого исключения на UDPS.Active:=false;
я уже из dll форму выбросил, вот код dll
в вызывающей программе в одной кнопке загрузить в другой выгрузить и всё
library MyDll;
uses
SysUtils,Classes, Forms,
Windows, Dialogs, IdUDPServer, IdBaseComponent, IdComponent,
IdUDPBase, IdUDPClient, IdSocketHandle;
{$R *.res}
var
UDPS: TIdUDPServer;
procedure MyDLLProc(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then begin
if UDPS.Active then begin
try
UDPS.Active:=false;
except
on e:exception do
ShowMessage(e.classtype.ClassName + ' ' + e.message);
end;
end;
UDPS.Free;
end;
end;
begin
DLLProc := @MyDLLProc;
UDPS:=TIdUDPServer.Create(Application);
UDPS.DefaultPort:=21888;
UDPS.BroadcastEnabled:=true;
UDPS.Active:=true;
ShowMessage('Load Ok');
end.
Digitman (2004-03-22 14:19:00) [17]проверь, нет ли исключения
procedure MyDLLProc(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then
begin
if UDPS.Active then
try
UDPS.Active := False;
except
on e:exception do
ShowMessage(e.classtype + ' ' + e.message);
end;
frmMain1.Free;
end;
end;
alin (2004-03-22 14:04:00) [18]да зависает именно при нажатии F7 на этой выделенной строчке
будем дальше искать
Digitman (2004-03-22 12:26:00) [19]procedure MyDLLProc(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then
begin
if UDPS.Active then
UDPS.Active := False;
frmMain1.Free;
end;
end;
поставь на отмеченной строке брейкпойнт, поймай его, сделай шаг (F8), убедись, что "вис" происходит именно на этой строке .. в противном случае убедись что эта строчка не вызывает исключения (равно как и следующая)
причин "виса" может быть всего 2 : либо в ходе деактивации listener thread не завершается либо при деактивации происходит искл.ситуация
только не спрашивай, что такое брейкпойнт, что такое "шаг" и пр. - это страшная тайна
alin (2004-03-22 12:11:00) [20]нет не помогает всё равно зависает на всегда