Форум: "Основная";
Текущий архив: 2002.11.04;
Скачать: [xml.tar.bz2];
ВнизDLL & Threads Найти похожие ветки
← →
Dynamit (2002-10-22 16:57) [0]Может знает кто, помогите. Проблема такая - в DLL создается поток в котором происходит запрос к БД. Сигнал готовности - сообщение приложению. В принципе все отрабатывает, кроме выгрузки библиотеки. Создание потока происходит таким образом:
Function QueryExec(AHndl: THandle; Number: Integer; ASQL, AFNum: PChar): THandle; SafeCall;
var
QueryForm: TFQThread;
begin
Application.Handle:=AHndl;
QueryForm := TFQThread.Create(Application);
QueryForm.Visible:=False;
With TQueryThread.Create(QueryForm) Do
Begin
Result:=ThreadId;
QueryForm.UNum:=Number;
QueryForm.USQL:=String(ASQL);
QueryForm.UFName:=String(AFNum);
QueryForm.UHndl:=AHndl;
OnTerminate:=Term;
Resume;
End;
//QueryForm.Free;
end;
Если раскоментировать освобождение QueryForm - будет ошибка при выполнении тела потока.
Если же не создавать поток (убрать блок With) и раскоментировать освобождение QueryForm, то функция выгрузки библиотеки отрабатывает нормально.
Метод Create для TThread:
constructor TQueryThread.Create(AQueryForm: TFQThread);
begin
QueryForm := AQueryForm;
FreeOnTerminate := True;
inherited Create(True);
end;
????
← →
Игорь Шевченко (2002-10-22 17:22) [1]А Execute для TThread ?
← →
Bis (2002-10-22 17:27) [2]ты кажется дважды пытаешь освободить поток
выбирай или FreeOnTerminate или сам вызывай Free
← →
NailS (2002-10-22 17:53) [3]
> Если раскоментировать освобождение QueryForm - будет ошибка
> при выполнении тела потока.
Не удивительно.
У тебя же поток стал работать после Resume, и небось в работе использует QueryForm, которой ты следом за вызовом Resume делаешь QueryForm.Free.
QueryExec - это функция экспортируемая из длл?
← →
Набережных С. (2002-10-22 17:57) [4]>Если раскоментировать освобождение QueryForm - будет ошибка при выполнении тела потока
Еще бы, ведь поток наверняка обращается к ней или ее компонентам, а она уже уничтожена.
В принципе все отрабатывает, кроме выгрузки библиотеки
Вероятно из той же оперы - пытаешься выгрузить DLL, когда поток еще не завершился.
← →
Dynamit (2002-10-23 08:37) [5]
> Игорь Шевченко
Вот метод Execute:
procedure TQueryThread.Execute;
begin
Try
try
with QueryForm do
begin
SThr.SessionName := Format("A%s%x", [SThr.Name,UNum]);
DB1.SessionName := SThr.SessionName;
DB1.DatabaseName := Format("A%s%x", [DB1.Name,UNum]);
QInd.SessionName := DB1.SessionName;
QInd.DatabaseName := DB1.DatabaseName;
QInd.SQL.Text:=USQL;
If (Not Terminated) Then
Begin
Table1.TableName:=Format(UFName,[UNum]);
Table1.SessionName:=SThr.SessionName;
CrtRcv; // Создание таблицы-приемника
UCnt:=BathMv; // Получение данных
SendMsg(PM_DATAREADY,UNum,UCnt) //Данные готовы
End;
End;
except
on E: Exception do
begin
{ Display any error we receive on the status line }
MessageText := Format("Хмм "+QueryForm.QInd.SQL.Text+#13+" %s: %s.", [E.ClassName, E.Message]);
Synchronize(DisplayMessage);
end;
End;
Finally
QueryForm.QInd.Close;
QueryForm.SThr.Active:=False;
QueryForm.DB1.Connected:=False;
End;
end;
> Bis (22.10.02 17:27)
> ты кажется дважды пытаешь освободить поток
> выбирай или FreeOnTerminate или сам вызывай Free
Я освобождаю форму, а не поток.
> NailS
Дк я ведь согласен, но делать то что-то надо, а освобождал форму только ради эксперимента, ведь где-то ее надо освобождать!
> Набережных С.
Из метода Execute для потока (приведено выше), видно, что я ловлю сообщение о готовности данных. Вот по его приходу я жду еще Sleep(100), и только затем выгружаю библиотеку. (Кстати насколько верно утверждение, что после завершения метода Execute освобождается сам объект потока?).
Так что, пока ситуация темна как ночь!
← →
Bis (2002-10-23 09:11) [6]Я тут не то в прошлый раз написал, каюсь
Про освобождение формы уже писали, у тебя она автоматически убъется Application. Если хочешь сам, то в методе OnClose формы поставь значение caFreе
← →
panov (2002-10-23 09:37) [7]
QueryForm.Free;
вызывай в кодеExecute
- в конце.
With TQueryThread.Create(QueryForm) Do
Begin
Result:=ThreadId;
QueryForm.UNum:=Number;
QueryForm.USQL:=String(ASQL);
QueryForm.UFName:=String(AFNum);
QueryForm.UHndl:=AHndl;
OnTerminate:=Term;
Resume;
End;
QueryForm.Free;
//здесь у тебя форма уничтожается до окончания работы потока, поэтому и возникает exception
← →
Dynamit (2002-10-23 09:56) [8]
> panov
Еще раз повторяю - это для експеримента, потому и закоментировано.
> Bis
caFree не помогает :(
← →
panov (2002-10-23 10:06) [9]>Dynamit (23.10.02 09:56)
Прочитай внимательно то, что написано у меня...
Уничтожай форму в методе Execute, а не в основном потоке.
← →
Bis (2002-10-23 10:22) [10]сделай глобальную переменную и напиши уничтожение в OnTerminate, больше идей нету ...
← →
Dynamit (2002-10-23 10:28) [11]
> panov
Извини, начало просмотрел :)
Но все равно нет в жизни счастья - глюк остался.
Есть у меня еще одна мысль - ведь в функции QueryExec переменная QueryForm - локальная, а значит по завершении будет недоступна...
Нет, перенес ее во внешний блок Var - глобальный для DLL - глюк остался.
← →
Dynamit (2002-10-23 10:30) [12]
> Bis
Уже сделал - результат тот же. Главное ведь что обидно - данные на экране я получаю, а работать могу только до FreeLibrary :(
← →
Набережных С. (2002-10-23 16:21) [13]Вынужден настаивать(хотя, разумеется, могу и ошибиться) - наиболее вероятно, что при освобождении DLL ошибка возникает из-за того, что код, находящийся в библиотеке, в это время выполняется. "жду еще Sleep(100)" - не понятно, где. Лучше покажи, как ждешь. А ждать лучше не сообщения, а изменения состояния хендла - это гарантирует окончание потока. И форму можно освободить по окончании ожидания. Но возникновение OnTerminate, как и факт уничтожения TThread вызовом деструктора по флагу FreeOnTerminate - еще не гарантия, что код потока завершился. Точнее, обработчик OnTerminate вызывается, когда поток еще исполняется, но после возврата из Execute. Единственная, повторюсь, гарантия завершения кода потока - ожидание хендла(можно и через TThread.WaitFor, хотя имхо лучше через API).
>Кстати насколько верно утверждение, что после завершения метода Execute освобождается сам объект потока?
Дельфийская реализация гарантирует вызов деструктора TThread по окончании Execute, если FreeOnTerminate = true, но это еще не гарантия завершения потока в понимании ОС. Далее следует еще выполнение некоторого завершающего кода в контексте потока.
← →
Dynamit (2002-10-23 16:37) [14]
> Набережных С.
Маленькая просьба, если не трудно, покажи реализацию любого из описанных тобой методов ожидания завершения потока. Обещаю проработать и сообщить результаты :)
А в плане того, где жду - это здесь:
procedure TForm1.Button2Click(Sender: TObject);
Var
LibHandle: THandle;
QExec: TQueryExec;
CurHndl: LongInt;
begin
LibHandle:=LoadLibrary("ASQuery.Dll");
Try
If LibHandle=0 Then
Raise EDLLLoadError.Create("Не могу загрузить DLL");
@QExec:=GetProcAddress(LibHandle,"QueryExec");
If Not (@QExec=nil) Then
CurHndl:=QExec(Handle, 1, PChar(Query), PChar("Tmp\Proba.db"));
Button2.Enabled:=False;
Button1.Enabled:=True;
fReady:=False;
While Not fReady Do
Begin
Application.ProcessMessages;
Sleep(100);
End;
Sleep(10);
@QExec:=nil;
Table1.Open;
Finally
FreeLibrary(LibHandle);
End;
end;
Это тестовый вариант, так что строго не судите ;)
← →
Набережных С. (2002-10-23 18:04) [15]Например, так:
Function QueryExec(AHndl: THandle; Number: Integer; ASQL, AFNum: PChar): THandle; SafeCall
begin
...
With TQueryThread.Create(QueryForm) Do
Begin
Result:=Handle;
....
end;
procedure TForm1.Button2Click(Sender: TObject);
Var
LibHandle: THandle;
QExec: TQueryExec;
CurHndl: LongInt;
HRes: integer;
begin
LibHandle:=LoadLibrary("ASQuery.Dll");
Try
If LibHandle=0 Then
Raise EDLLLoadError.Create("Не могу загрузить DLL");
@QExec:=GetProcAddress(LibHandle,"QueryExec");
If @QExec <> nil Then
begin
CurHndl:=QExec(Handle, 1, PChar(Query), PChar("Tmp\Proba.db"));
Button2.Enabled:=False;
Button1.Enabled:=True;
fReady:=False;
repeat
Application.ProcessMessages;
HRes:=WaitForSingleObject(CurHandle,100);
until (HRes <> WAIT_TIMEOUT) or fReady;
if HRes = WAIT_ABANDONED then RaiseLastWin32Error
else if fReady then (отменено)
@QExec:=nil;
Table1.Open;
end;
Finally
FreeLibrary(LibHandle);
End;
end;
← →
Dynamit (2002-10-24 08:55) [16]При выгрузке библиотеки осталась ошибка Access violation.
Но был странный момент - не знаю связано это или нет:
При первом запуске после загрузки компа при появлении данных в таблице (Table1.Open) ошибок не было, и можно было работать с таблицей, но при закрытии библиотеки произошла ошибка доступа (Access violation) с зависанием проги (была закрыта с помощью диспетчера). При последующих запусках программа зависала при выгрузке библиотеки (т.е. таблицу я видел, но сделать ничего не успевал). Поставил showMessage после FreeLibrary(LibHandle) - ошибку выдал раньше, чем мое сообщение.
Есть идея попробовать блок Try ... Exception End для удаления ошибки - но ведь это не правильно!
Других идей нет :( и все опускается вместе с руками!
← →
Dynamit (2002-10-24 09:35) [17]Ураааа!
Все заработало. Объединение последнего совета Набережных С. с предудущими советами (не всеми), пара тройка десятков опытов - вот и все, что нужно было для успеха.
Всем участникам - огромное человеческое спасибо!
Отдельное спасибо господину Набережных С.
До встречи.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2002.11.04;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.01 c