Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 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.063 c
2-1179581025
Rafik
2007-05-19 17:23
2007.06.10
TListView


3-1174296643
fd979
2007-03-19 12:30
2007.06.10
Получение пароля пользователя в MS SQL Server?


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


9-1153230016
DevilDevil
2006-07-18 17:40
2007.06.10
Физический Движок


2-1179798888
delphino
2007-05-22 05:54
2007.06.10
Копирование набора Query в Table





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