![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Зависание программы при обращении к БД из отдельного потока [D6]
DelphiN! © (2007-03-23 08:24:00)Есть процедура, которая запускается из отдельных потоков и делает выборку из небольшой таблицы(<200 записей), а далее ищет и возвращает значение определененого поля, иногда при выполнении кода
DataSet.Open;все приложение зависает, без вывода каких либо ошибок, отладчик останавливается на данной строчке и далее выполнение не проходит, в чем может быть причина зависания ума не приложу, вот код данной процедуры :
function TDATA.IpToCardNo(IP: String): String;
var
DataSet: TIbDataSet;
Transaction: TIbTransaction;
begin
try
DataSet := TIbDataSet.Create(nil);
Transaction := TIbTransaction.Create(nil);
DataSet.Database := IBDatabase1;
Transaction.DefaultDatabase := IBDatabase1;
DataSet.Transaction := Transaction;
Result := '';
DataSet.SelectSQL.Text := 'SELECT * FROM SEANSES';
DataSet.Open; //Зависает программа тут
DataSet.FetchAll;
DataSet.First;
if DataSet.Locate('COMP_',IP,[loCaseInsensitive]) then
Result := DataSet.FieldByName('IsCard_').AsString;
finally
DataSet.Free;
Transaction.Free;
end;
end;
Сейчас есть мысли, что данная проблемма происходит, когда процедуру вызывают более N-ного числа потоков одновоременно и в следствии того что на компьютере установлена ОС Windows XP обладающая рядом ограничений на колличество сетевых подключений, подключение к БД не происходит, но почему не появляется сообщение об ошибке и программа просто зависает?
PS: Используется СУБД Firebird 1.5, база данных расположена на том-же компьютере, на котором осуществляется работа приложения
Заранее благодарен за любую помощь в решении данной проблеммы!
Сергей М. (2007-03-23 16:09:00) [1]
> DelphiN! © (23.03.07 14:26) [20]
Если бы ты еще понял, что и для чего ты там "указал", то честь и хвала тебе была бы)
DelphiN! (2007-03-23 14:26:00) [2]Точно! указал 127.0.0.1 и все заработало, и больше не зависало!! Спасибо всем!!!!
Desdechado (2007-03-23 13:30:00) [3]> DataBase.DatabaseName := 'C:\BASE.FDB';
Такой способ подключения архаичен и чреват проблемами при одновременной работе нескольких подключений. О чем тоже написано в документации. Использовать 127.0.0.1
ЮЮ (2007-03-23 13:20:00) [4]> Дебаггер туда не заходит :(
A Use Debug DCUs в проекте включил?
Val (2007-03-23 12:50:00) [5]напиши c localhost все-таки, как положено.
DelphiN! (2007-03-23 12:48:00) [6]
> ЮЮ © (23.03.07 12:39) [15]
А на каком, интересно, сервере будет искаться БД, если он не указан ( это к знатаким IB)?
На локальном
> > DataBase.Connected := true; // Зависает тут!
>
> А если войти вовнутрь дебаггером?
Дебаггер туда не заходит :(
ЮЮ (2007-03-23 12:39:00) [7]А на каком, интересно, сервере будет искаться БД, если он не указан ( это к знатаким IB)?
> DataBase.Connected := true; // Зависает тут!
А если войти вовнутрь дебаггером?
DelphiN! (2007-03-23 12:20:00) [8]Создаю новое подключение к БД в новом потоке, пытаюсь открыть соединение и поток снова зависает!
Сделал следующее :
function TDATA.IpToCardNo(IP: String; DataSet: TibDataSet): String;
begin
try
Result := '';
DataSet.SelectSQL.Text := 'SELECT * FROM SEANSES WHERE COMP_ = '''+IP+'''';
DataSet.Open;
Result := DataSet.FieldByName('IsCard_').AsString;
except
on E:Exception do
MessageBox(0, PChar(E.Classname + ' ' + E.Message), '', MB_OK or MB_SETFOREGROUND);
end;
end;
procedure TMain.ServerSocketGetThread(Sender: TObject;
ClientSocket: TServerClientWinSocket;
var SocketThread: TServerClientThread);
begin
SocketThread := TServerThread.Create(false, ClientSocket);
end;
procedure TServerThread.ClientExecute;
var
SockStream : TWinSocketStream;
FileInfo : array [0..10000] of char;
FileStream : TStream;
BytesSent : LongInt;
nRead : Integer;
strl,Params: TStringList;
cIP,IP: String;
DataSet: TibDataSet;
DataBase: TibDataBase;
Transaction: TibTransaction;
begin
try
strl := TStringList.Create;
Params := TStringList.Create;
SockStream := TWinSocketStream.Create(ClientSocket,10000);
if SockStream.WaitForData(10000) then
begin
if not ClientSocket.Connected then
Exit;
...
DataSet := TIbDataSet.Create(nil);
Transaction := TIbTransaction.Create(nil);
DataBase := TIbDataBase.Create(nil);
DataSet.Database := DataBase;
DataSet.Transaction := Transaction;
Transaction.DefaultDatabase := DataBase;
DataBase.DatabaseName := 'C:\BASE.FDB';
DataBase.Params.Text := 'user_name=SYSDBA'+#13#10+'password=masterkey';
DataBase.LoginPrompt := false;
DataBase.DefaultTransaction := Transaction;
DataBase.Connected := true; // Зависает тут!
IP := ClientSocket.RemoteAddress;
cIP := IpToCardNo(IP);
finally
DataSet.Free; DataSet := nil;
DataBase.Free; DataBase := nil;
Transaction.Free; Transaction := nil;
SockStream.Free;
SockStream := nil;
if ClientSocket.Connected then
ClientSocket.Close;
end;
end;
В чем теперь может быть дело??
Desdechado (2007-03-23 10:58:00) [9]Дополню Romkin © (23.03.07 10:36) [11].
Причина в том, что клиент IB\FB неthread-safe, о чем написано в документации. Поэтому не должно быть 2 одновременных обращений к серверу через одно соединение.
Сергей М. (2007-03-23 10:46:00) [10]
> Теперь программа зависает
"Зависает" не программа, а доп.поток.
См. [9],[10],[11]
Romkin (2007-03-23 10:36:00) [11]Да что за советы? У него коннект-то к БД в основном потоке!
Объясняю: каждый поток должен иметь собственный коннект к БД. Либо защищай обращения.
Johnmen (2007-03-23 09:43:00) [12]и ещё
вот это лишнее DataSet.First;
вот это не гарантируется DataSet.RecordCount > 0
Johnmen (2007-03-23 09:41:00) [13]>DelphiN! ©
Настоятельно рекомендую : один поток - один коннект с сервером. У тебя же на все потоки один единственный коннект....
DelphiN! (2007-03-23 09:40:00) [14]Причем зависает программа "через раз" иногда выполнит процедуру успешно, а иногда зависнет при выполнении
DelphiN! (2007-03-23 09:39:00) [15]Переделал процедуру следующим образом :
function TDATA.IpToCardNo(IP: String): String;
var
DataSet: TIbDataSet;
Transaction: TIbTransaction;
begin
try
try
Result := '';
DataSet := TIbDataSet.Create(nil);
Transaction := TIbTransaction.Create(nil);
DataSet.Database := IBDatabase1;
Transaction.DefaultDatabase := IBDatabase1;
DataSet.Transaction := Transaction;
DataSet.SelectSQL.Text := 'SELECT * FROM SEANSES WHERE COMP_ = '''+IP+'''';
DataSet.Open;
DataSet.First;
if DataSet.RecordCount > 0 then
Result := DataSet.FieldByName('IsCard_').AsString;
finally
DataSet.Free;
Transaction.Free; //теперь зависает тут
end;
except
on E:Exception do
MessageBox(0, PChar(E.Classname + ' ' + E.Message), '', MB_OK or MB_SETFOREGROUND);
end;
end;
Теперь программа зависает приTransaction.Free;без какого либо сообщения об ошибке. В чем может быть дело?
Сергей М. (2007-03-23 09:00:00) [16]
> почему не появляется сообщение об ошибке и программа просто
> зависает?
Потому что исключения в доп.потоках следует перехватывать и обрабатывать явно
procedure TMyThread.Execute;
begin
try
.... здесь происходят чудеса ...
except
on E:Exception do
MessageBox(0, PChar(E.Classname + ' ' + E.Message), '', MB_OK or MB_SETFOREGROUND);
end;
end;
DelphiN! (2007-03-23 08:52:00) [17]
> Sergey13 © (23.03.07 08:38) [3]
Кстати сколько это примерно "N-ного числа потоков"?
Сейчас не больше 10ти одновременных потоков, в будущем не больше 50ти(максимум)
> Sergey13 © (23.03.07 08:38) [3]
С потоками чего нибудь намудрил.
Поток создаю так :
Обработчик события OnGetThread компонента ServerSocket, в который приходят запросы от не более чем 400 клиентов:
procedure TMain.ServerSocketGetThread(Sender: TObject;
ClientSocket: TServerClientWinSocket;
var SocketThread: TServerClientThread);
begin
SocketThread := TServerThread.Create(false, ClientSocket);
end;
procedure TServerThread.ClientExecute;
var
SockStream : TWinSocketStream;
FileInfo : array [0..10000] of char;
FileStream : TStream;
BytesSent : LongInt;
nRead : Integer;
strl,Params: TStringList;
cIP,IP: String;
begin
try
strl := TStringList.Create;
Params := TStringList.Create;
SockStream := TWinSocketStream.Create(ClientSocket,10000);
if SockStream.WaitForData(10000) then
begin
if not ClientSocket.Connected then
Exit;
...
IP := ClientSocket.RemoteAddress;
cIP := IpToCardNo(IP);
finally
SockStream.Free;
SockStream := nil;
if ClientSocket.Connected then
ClientSocket.Close;
end;
end;
sniknik (2007-03-23 08:45:00) [18]> Согласен, это ускорит работу нерабочей процедуры.
и возможно исключит возможную взаимоблокировку... (транзакции ведь в FB есть блокирующие? и эта какая?)
> А что делать с зависаниями?
а вот проверь, и может больше ничего делать и не надо будет...
хотя, мне еще не нравится создание компонент в функции, одноразовое... нельзя их както в потоке, в начале создавать и освобождать в конце? а внутри просто использовать.
Sergey13 (2007-03-23 08:38:00) [19]> [2] DelphiN! © (23.03.07 08:34)
С потоками чего нибудь намудрил. Кстати сколько это примерно "N-ного числа потоков"?
DelphiN! (2007-03-23 08:34:00) [20]Согласен, это ускорит работу нерабочей процедуры. А что делать с зависаниями?