Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.06.10;
Скачать: CL | DM;

Вниз

Зависание программы при обращении к БД из отдельного потока   Найти похожие ветки 

 
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;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.017 c
15-1179189469
StartUp
2007-05-15 04:37
2007.06.10
Фичи в редакторе Дельфи в виде картинок


2-1179384606
pathfinder
2007-05-17 10:50
2007.06.10
Запуск консольного приложения из программы.


2-1179571010
Nijaz
2007-05-19 14:36
2007.06.10
Как построить график


11-1161659057
vampir_infernal
2006-10-24 07:04
2007.06.10
class function и KOL


2-1179312569
Ксандр
2007-05-16 14:49
2007.06.10
Просмотр HTML кода