Форум: "Базы";
Текущий архив: 2007.06.10;
Скачать: [xml.tar.bz2];
ВнизЗависание программы при обращении к БД из отдельного потока Найти похожие ветки
← →
DelphiN! © (2007-03-23 08:24) [0]Есть процедура, которая запускается из отдельных потоков и делает выборку из небольшой таблицы(<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, база данных расположена на том-же компьютере, на котором осуществляется работа приложения
Заранее благодарен за любую помощь в решении данной проблеммы!
← →
Sergey13 © (2007-03-23 08:30) [1]А какой смысл тянуть весь (хоть и небольшой) набор данных на клиента? Почему не вытягивать только нужное поле по заданному IP-шнику тем же запросом?
← →
DelphiN! © (2007-03-23 08:34) [2]Согласен, это ускорит работу нерабочей процедуры. А что делать с зависаниями?
← →
Sergey13 © (2007-03-23 08:38) [3]> [2] DelphiN! © (23.03.07 08:34)
С потоками чего нибудь намудрил. Кстати сколько это примерно "N-ного числа потоков"?
← →
sniknik © (2007-03-23 08:45) [4]> Согласен, это ускорит работу нерабочей процедуры.
и возможно исключит возможную взаимоблокировку... (транзакции ведь в FB есть блокирующие? и эта какая?)
> А что делать с зависаниями?
а вот проверь, и может больше ничего делать и не надо будет...
хотя, мне еще не нравится создание компонент в функции, одноразовое... нельзя их както в потоке, в начале создавать и освобождать в конце? а внутри просто использовать.
← →
DelphiN! © (2007-03-23 08:52) [5]
> 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;
← →
Сергей М. © (2007-03-23 09:00) [6]
> почему не появляется сообщение об ошибке и программа просто
> зависает?
Потому что исключения в доп.потоках следует перехватывать и обрабатывать явно
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 09:39) [7]Переделал процедуру следующим образом :
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;
без какого либо сообщения об ошибке. В чем может быть дело?
← →
DelphiN! © (2007-03-23 09:40) [8]Причем зависает программа "через раз" иногда выполнит процедуру успешно, а иногда зависнет при выполнении
← →
Johnmen © (2007-03-23 09:41) [9]>DelphiN! ©
Настоятельно рекомендую : один поток - один коннект с сервером. У тебя же на все потоки один единственный коннект....
← →
Johnmen © (2007-03-23 09:43) [10]и ещё
вот это лишнее DataSet.First;
вот это не гарантируется DataSet.RecordCount > 0
← →
Romkin © (2007-03-23 10:36) [11]Да что за советы? У него коннект-то к БД в основном потоке!
Объясняю: каждый поток должен иметь собственный коннект к БД. Либо защищай обращения.
← →
Сергей М. © (2007-03-23 10:46) [12]
> Теперь программа зависает
"Зависает" не программа, а доп.поток.
См. [9],[10],[11]
← →
Desdechado © (2007-03-23 10:58) [13]Дополню Romkin © (23.03.07 10:36) [11].
Причина в том, что клиент IB\FB не thread-safe, о чем написано в документации. Поэтому не должно быть 2 одновременных обращений к серверу через одно соединение.
← →
DelphiN! © (2007-03-23 12:20) [14]Создаю новое подключение к БД в новом потоке, пытаюсь открыть соединение и поток снова зависает!
Сделал следующее :
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;
В чем теперь может быть дело??
← →
ЮЮ © (2007-03-23 12:39) [15]А на каком, интересно, сервере будет искаться БД, если он не указан ( это к знатаким IB)?
> DataBase.Connected := true; // Зависает тут!
А если войти вовнутрь дебаггером?
← →
DelphiN! © (2007-03-23 12:48) [16]
> ЮЮ © (23.03.07 12:39) [15]
А на каком, интересно, сервере будет искаться БД, если он не указан ( это к знатаким IB)?
На локальном
> > DataBase.Connected := true; // Зависает тут!
>
> А если войти вовнутрь дебаггером?
Дебаггер туда не заходит :(
← →
Val © (2007-03-23 12:50) [17]напиши c localhost все-таки, как положено.
← →
ЮЮ © (2007-03-23 13:20) [18]> Дебаггер туда не заходит :(
A Use Debug DCUs в проекте включил?
← →
Desdechado © (2007-03-23 13:30) [19]> DataBase.DatabaseName := "C:\BASE.FDB";
Такой способ подключения архаичен и чреват проблемами при одновременной работе нескольких подключений. О чем тоже написано в документации. Использовать 127.0.0.1
← →
DelphiN! © (2007-03-23 14:26) [20]Точно! указал 127.0.0.1 и все заработало, и больше не зависало!! Спасибо всем!!!!
← →
Сергей М. © (2007-03-23 16:09) [21]
> DelphiN! © (23.03.07 14:26) [20]
Если бы ты еще понял, что и для чего ты там "указал", то честь и хвала тебе была бы)
Страницы: 1 вся ветка
Форум: "Базы";
Текущий архив: 2007.06.10;
Скачать: [xml.tar.bz2];
Память: 0.51 MB
Время: 0.042 c