Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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
14-11389
Шурик Ш
2002-10-16 18:10
2002.11.04
Злой админ отрубил доступ к аське


14-11410
bobby
2002-10-12 18:54
2002.11.04
Как задать брекпоинт


4-11536
Serd_hhc
2002-09-21 15:39
2002.11.04
Для Гуру....


6-11366
Oduvan
2002-09-01 16:45
2002.11.04
Научите пожалуйста меня раскодировать строки!!! Плиз!


1-11187
Андрей Прокофьев
2002-10-24 14:18
2002.11.04
Как включить (и прочитать) в ресурс анимационный курсор





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