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

Вниз

Многопоточность и DB-компоненты   Найти похожие ветки 

 
Ega23 ©   (2005-11-22 09:12) [0]

Вопрос может показаться странным, а может даже и глупым. Дело в том, что никогда не работал с потоками.
Вопрос следующий: есть главный поток, в нём "живёт" DBGrid. Есть дополнительный поток, в нём крутится один и тот же запрос. Если DBGrid из основного потока смотрит на НД в отдельном - могут ли тут быть какие-нибудь подводные камни?

З.Ы. Напомните, что там про Архангельского было с TThread.Synchronize?  :о)


 
Savek   (2005-11-22 09:25) [1]

А зачем НД для Грида помещать в отдельный поток?

Synchronize используется для вызова методов VCL


 
Ega23 ©   (2005-11-22 09:26) [2]


> А зачем НД для Грида помещать в отдельный поток?


Чтобы основной разгрузить.


 
ANB ©   (2005-11-22 09:26) [3]


> Ega23 ©   (22.11.05 09:12)

Подключать грид к невыполненному запросу смысла нету. Долго ли выполняется запрос ? Если быстро - то удобнее повесить его на таймер.


 
Ega23 ©   (2005-11-22 09:28) [4]


> Подключать грид к невыполненному запросу смысла нету. Долго
> ли выполняется запрос ? Если быстро - то удобнее повесить
> его на таймер.


Запрос выполняется достаточно быстро (~ 30 мс.) На таймере сейчас висит. Плохо. Всё из-за этой протокольной смотрелки тормозит.


 
ANB ©   (2005-11-22 09:39) [5]

Странно. На таймере не должно тормозить. Тебе по любому даже если в отдельном потоке запрос выполнять, придется синхронизировать, что запрос выполнен и его можно показывать. А если поток останавливать, когда запрос выполнен, но не разрушать и перекачивать из него данные ? Тогда, по идее, и проблем с синхронизацией быть не должно.


 
Ega23 ©   (2005-11-22 09:45) [6]


> Странно. На таймере не должно тормозить. Тебе по любому
> даже если в отдельном потоке запрос выполнять, придется
> синхронизировать, что запрос выполнен и его можно показывать.
>  А если поток останавливать, когда запрос выполнен, но не
> разрушать и перекачивать из него данные ? Тогда, по идее,
>  и проблем с синхронизацией быть не должно.
>


Давай я попробую более подробно рассказать.
Есть некая система неких объектов. Объекты обмениваются между собой сообщениями. Эти сообщения могут быть перехвачены специальным объектом и запротоколированы в БД. Также, на некоторые сообщения, в реальном времени нужно выводить информацию на экран оператора.
Вся система работает и в одном потоке, но подтормаживает. Профилирование показало, что основные тормоза - как раз на выборке данных из протокола. Сейчас думаем, как ситуацию обойти. Хотим попробовать вынести чтение данных в отдельный поток.


 
Juice ©   (2005-11-22 10:48) [7]


> Ega23 ©

Я в своих приложениях уже давно практикую такой подход (если я правильно понял). Но я деляю немного иначе, датаконтролс и датасеты я размещаю в одном потоке (главном) а сам запрос выполняю в служебном потоке. Сначала так работал с IBX/FibPLUS, теперь уже достаточное время с DBX, никаких проблем не возникало.


 
Ega23 ©   (2005-11-22 10:50) [8]


> Juice ©   (22.11.05 10:48) [7]
>
> Я в своих приложениях уже давно практикую такой подход (если
> я правильно понял). Но я деляю немного иначе, датаконтролс
> и датасеты я размещаю в одном потоке (главном) а сам запрос
> выполняю в служебном потоке. Сначала так работал с IBX/FibPLUS,
>  теперь уже достаточное время с DBX, никаких проблем не
> возникало.
>


Вопрос несколько некорректен, но всё-таки: можешь показать пример кода?  :о)


 
Juice ©   (2005-11-22 11:19) [9]

Могу, только вам придется немного в нем разобраться - я себе для удобства написал юнит который это все делает вызовом одной функции и отображат окошко "подождите", использую не только для запросов но и прочих длительных действий.

Вот смысловая часть этого "служебного" юнита:

INTERFACE

type
 // Это формочка что показывается когда идет длительная процедура
 TfmWait = class(TForm)
   pbProgress: TProgressBar;
   lbCaption: TLabel;
   tmrProgress: TTimer;
   tmrShow: TTimer;
   procedure tmrProgressTimer(Sender: TObject);
   procedure tmrShowTimer(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

// это обьявление прототипа служебной функции :
TJobParams = array of Variant;
 TJobProc = procedure (out Res : PVAriant; params : TJobParams; JobThread:TThread) of object;

//Это функция которая выполняет длит.задачу без отображения окна:
 function  ExecInThread(const func : TJobProc; Res:PVariant; params: array of Variant) : TThread;
//Это функция которая выполняет длит.задачу показывая окно:
 procedure ExecInThreadFm(const func : TJobProc; Res:PVariant; params: array of Variant; caption : string; SecToWait:integer);



IMPLEMENATATION

{ TJobThread }
procedure TJobThread.Execute;
var
 JobProc:TJobProc;
begin
 try
   try
     JobProc := func;
     JobProc(Res, Params, Self);
   except
     on E:Exception do
     begin
       Res^:=-1002.1002;                     //Error
       Application.MessageBox(PChar(E.Message), "Помилка у службовому потоці TJobThread.Execute");
     end;
   end;
 finally
   if Res^=varEmpty then Res^:=-1000.1000;   //Empty Result
 end;
end;

function ExecInThread(const func:TJobProc; Res:PVariant; params:array of Variant):TThread;
var
 JobThread : TJobThread;
 i : integer;  
begin
 JobThread := TJobThread.Create(true);
 try
   JobThread.func := func;
   JobThread.res := res;
   JobThread.FreeOnTerminate := true;
   SetLength(JobThread.params, Length(params));
   for i:=0 to High(params) do
   begin
     JobThread.params[i] := params[i];
   end;
   JobThread.Resume;
   Result:=JobThread;
 except
   on E:Exception do
   begin
     if not JobThread.Suspended then JobThread.Suspend;
     JobThread.Free;
     E.Message := E.Message + " (помилка виникла в функції ExecInThread)";
     raise;
   end;
 end;
end;

procedure ExecInThreadFm(const func : TJobProc; Res:PVariant; params: array of Variant; caption : string; SecToWait:integer);
var
 JobThread : TThread;
 fmWait : TfmWait;
begin
 try
   JobThread:=ExecInThread(func, Res, params);
   fmWait := TfmWait.Create(Application);
   fmWait.lbCaption.Caption := Caption;
   fmWait.pbProgress.Max := SecToWait*10;
   fmWait.tmrProgress.Enabled := true;
   try
     repeat
       Application.ProcessMessages;
     until (Res^<>varEmpty) or (fmWait.pbProgress.Position = fmWait.pbProgress.Max);
     if VarIsFloat(Res^) and (Res^ = -1002.1002) then
       raise Exception.Create("У службовому потоці виникла помилка !");
     if fmWait.pbProgress.Position = fmWait.pbProgress.Max then
     begin
       TerminateThread(JobThread.Handle, 0);
       raise Exception.Create("Вичерпано час !");
     end;
     fmWait.pbProgress.Position := fmWait.pbProgress.Max;
   finally
     fmWait.Close;
     fmWait.Free;
   end;
 except
   on E:Exception do
   begin
     E.Message := E.Message + " (помилка виникла в функції ExecInThreadFm)";
     raise;
   end;
 end;
end;

//----------------ФОРМА ------------------------------------------------------//

procedure TfmWait.tmrProgressTimer(Sender: TObject);
begin
 pbProgress.StepIt;
end;

procedure TfmWait.tmrShowTimer(Sender: TObject);
begin
 Show;  
 tmrShow.Enabled := false;
 //в tmrShow интревал установлен в 0.5 секунды, т.е. если действие выполняется быстрее чем за 0.5 сек то форма не отображатеся, если прошло 0.5. сек - форма отображается. Это чтобы она зря не мелькала на экране.
end;


Вот пример использования:

procedure TMyForm.DBConnectJob(out Res: PVAriant; params: TJobParams; JobThread:TThread);
begin
 TSQLDataSet(Cardinal(params[0])).Open;
 TSQLDataSet(Cardinal(params[1])).Open;
 Res^ := 1;       //н.д. открыты успешно
end;

procedure TMyForm.btnProcessClick(Sender: TObject);
begin
 try
   dsOpers.Close;
   dsOpers.CommandText := "select * from ...";
   dsCustomers.Close;
   dsCustomers.CommandText := "select max(crole), ...";
   ExecInThreadFm(DBConnectJob, @Res, [Cardinal(dsOpers), Cardinal(dsCustomers)], "Іде отримання операцій ", 15);
 except
   on E:Exception do
   begin
     E.Message := E.Message + " (Помилка відбулась в методі "+Self.Name+".btnProcessClick) ";
     raise;
   end;
 end;
end;


 
Ega23 ©   (2005-11-22 11:21) [10]

Спасибо!
Дальше уже сам разберусь.


 
Ega23 ©   (2005-11-22 11:36) [11]

2 Juice ©   (22.11.05 11:19) [9]

А можно взглянуть на декларацию TJobThread  ?


 
Juice ©   (2005-11-22 11:41) [12]

Ой, забыл.

type
 TJobThread = class(TThread)
 protected
   procedure Execute; override;
 public
   func : TJobProc;
   res:   PVariant;
   params : TJobParams;
 end;

через params передаю в job-функцию параметры, через res возвращаю. В конце job-функции обязательно нужно присвоить Res^ что-то отличное от нуля.


 
Ega23 ©   (2005-11-22 11:42) [13]


> через params передаю в job-функцию параметры, через res
> возвращаю. В конце job-функции обязательно нужно присвоить
> Res^ что-то отличное от нуля.


Угу, это я уже понял. Спасибо.



Страницы: 1 вся ветка

Текущий архив: 2006.01.15;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.043 c
14-1134818862
СергоБ
2005-12-17 14:27
2006.01.15
Сохранение Timage в BMP иконку


2-1135668070
oleggar
2005-12-27 10:21
2006.01.15
где эти сообщения ?


2-1135592191
_Lucifer_
2005-12-26 13:16
2006.01.15
Выполнение обработке в одной форме, а показ прогресса в другой.


2-1135348869
Developerr
2005-12-23 17:41
2006.01.15
Как узнать находится ли курсор на форме или нет?


14-1135262887
BFG9k
2005-12-22 17:48
2006.01.15
Обьясните механизм извлечения dcu файла из пакета