Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Выполнение запросов в потоке, с использованием DOA


Страницы:   1 2 3

nobody ©   (2010-06-21 16:13:00) 

Вопрос к знатокам:
Почему при выполнении запроса в потоке залипает интерфейс всего приложения, вместо того, чтобы реагировать на действия пользователя во время выполнения запроса?

реализовано в коде следующим образом:

type

 TThreadControl = class(TThread)
 private
   FOracleDataSet: TOracleDataSet;
   FOracleQuery: TOracleQuery;
   FControl_C: TControl;
   FControl_A: TAction;
   FGrid: TcxGridDBTableView;
   FForm: TForm;
   FCollapse: boolean;
   FProcessMonitor: TProcessMonitor;
 protected
   FErrorMsg: string;
   procedure Execute; override;
   procedure LockControl;
   procedure UnLockControl;
   procedure ShowErrorMsg;
 public
   constructor Create(CreateSuspended: Boolean; OracleDataSet: TOracleDataSet;
     ProcessMonitor: TProcessMonitor; Control: TControl; Grid: TcxGridDBTableView; Form: TForm; FCollapse: boolean;
     LockControl: boolean = true);
     overload;
   constructor Create(CreateSuspended: Boolean; OracleQuery: TOracleQuery;
     ProcessMonitor: TProcessMonitor; Control: TControl; Grid: TcxGridDBTableView; Form: TForm; FCollapse: boolean;
     LockControl: boolean = true);
     overload;
   constructor Create(CreateSuspended: Boolean; OracleDataSet: TOracleDataSet;
     ProcessMonitor: TProcessMonitor; Control: TAction; Grid: TcxGridDBTableView; Form: TForm; FCollapse: boolean;
     LockControl: boolean = true);
     overload;
 end;

...

procedure TThreadControl.Execute;
begin
 inherited;
 try
   Synchronize(LockControl);
   if FOracleQuery <> nil then
     FOracleQuery.Execute;
   if FOracleDataSet <> nil then
   begin
     try
       FOracleDataSet.Close;
       FOracleDataSet.Open;
     except
       on E: Exception do
        begin
         FErrorMsg := E.Message;
         Synchronize(ShowErrorMsg);
        end;
     end;
   end;
 finally
   Synchronize(UnLockControl);
 end;
end;

MDI-приложение, дочерние формы загружаются из bpl-модулей.
В каждом модуле есть своя сессия, которая активизируется при необходимости выполнения запроса от этой формы.
Сессия отключается по истечению тайм-аута.
Если нужна еще какая-нить инфа, спрашивайте.


nobody   (2010-06-22 17:38:00) [1]

вообщем, нашел следующий выход:
запускаю экзешник из проводника, а потом средой подключаюсь к нему в памяти через Attach Process и все хорошо отлаживается и останавливается на всех бейкпоинтах... вот такой финт ушами.)


nobody   (2010-06-22 14:45:00) [2]


> Это мы ждем твоих комментариев

Все работает, но под отладкой вываливается куча ошибок и окно CPU
Вот примеры ошибок(идут одна за другой и нет им конца...)

вываливается на этом месте:
ntdll.RtlUnwind:
7C92ABC5 8BFF             mov edi,edi
7C92ABC7 55               push ebp
7C92ABC8 8BEC             mov ebp,esp
7C92ABCA 81EC7C030000     sub esp,$0000037c
7C92ABD0 A1C8E0977C       mov eax,[$7c97e0c8]
->7C92ABD5 56               push esi

Но если запускать без отладчика, то все работает без ошибок.
Да и еще один ньюанс:
Приложение построено по принципу подгружаемых bpl-ек.
БПЛька с датамодулем загружается сразу в авдресное пространство приложения и как раз во время ее загрузки под отладчиком происходят эти ошибки
вот еще порядок загрузки модулей в приложение:
Thread Start: Thread ID: 4468. Process KMS.exe (2680)
Process Start: C:\joe\KMS\bin\KMS.exe. Base Address: $00400000. Process KMS.exe (2680)
Module Load: KMS.exe. No Debug Info. Base Address: $00400000. Process KMS.exe (2680)
Module Load: ntdll.dll. No Debug Info. Base Address: $7C900000. Process KMS.exe (2680)
Module Load: KERNEL32.dll. No Debug Info. Base Address: $7C800000. Process KMS.exe (2680)
Module Load: rtl100.bpl. Has Debug Info. Base Address: $20000000. Process KMS.exe (2680)
Module Load: OLEAUT32.dll. No Debug Info. Base Address: $77110000. Process KMS.exe (2680)
Module Load: ADVAPI32.dll. No Debug Info. Base Address: $77DC0000. Process KMS.exe (2680)
Module Load: RPCRT4.dll. No Debug Info. Base Address: $77E70000. Process KMS.exe (2680)
Module Load: Secur32.dll. No Debug Info. Base Address: $77FE0000. Process KMS.exe (2680)
Module Load: GDI32.dll. No Debug Info. Base Address: $77F10000. Process KMS.exe (2680)
Module Load: USER32.dll. No Debug Info. Base Address: $7E360000. Process KMS.exe (2680)
Module Load: msvcrt.dll. No Debug Info. Base Address: $77C00000. Process KMS.exe (2680)
Module Load: ole32.dll. No Debug Info. Base Address: $774D0000. Process KMS.exe (2680)
Module Load: VERSION.dll. No Debug Info. Base Address: $77BF0000. Process KMS.exe (2680)
Module Load: MPR.dll. No Debug Info. Base Address: $71B00000. Process KMS.exe (2680)
Module Load: IMAGEHLP.dll. No Debug Info. Base Address: $76C80000. Process KMS.exe (2680)
Module Load: WSOCK32.dll. No Debug Info. Base Address: $71AB0000. Process KMS.exe (2680)
Module Load: WS2_32.dll. No Debug Info. Base Address: $71A90000. Process KMS.exe (2680)
Module Load: WS2HELP.dll. No Debug Info. Base Address: $71A80000. Process KMS.exe (2680)
Module Load: OLEACC.dll. No Debug Info. Base Address: $74C40000. Process KMS.exe (2680)
Module Load: MSVCP60.dll. No Debug Info. Base Address: $76050000. Process KMS.exe (2680)
Module Load: vcl100.bpl. Has Debug Info. Base Address: $200E0000. Process KMS.exe (2680)
Module Load: COMCTL32.dll. No Debug Info. Base Address: $5D5B0000. Process KMS.exe (2680)
Module Load: SHELL32.dll. No Debug Info. Base Address: $7C9C0000. Process KMS.exe (2680)
Module Load: SHLWAPI.dll. No Debug Info. Base Address: $77F60000. Process KMS.exe (2680)
Module Load: WINSPOOL.DRV. No Debug Info. Base Address: $72FC0000. Process KMS.exe (2680)
Module Load: comdlg32.dll. No Debug Info. Base Address: $76380000. Process KMS.exe (2680)
Module Load: oledlg.dll. No Debug Info. Base Address: $7DFC0000. Process KMS.exe (2680)
Module Load: DMMain.bpl. Has Debug Info. Base Address: $00680000. Process KMS.exe (2680)
и на этом месте попадает в циклическую ошибку.
---------------------------
Debugger Fault Notification
---------------------------
Project C:\joe\KMS\bin\KMS.exe faulted with message: 'access violation at 0x7c92abd5: write of address 0x00030d24'. Process Stopped. Use Step or Run to continue.
---------------------------
OK  

Среда разработки Code Gear 2007 SP3 Architect

Подскажите, что можно с этим сделать? как помочь отладчику не вывалиться на ошибке?


Ega23   (2010-06-22 12:49:00) [3]


> Жду ваших комментариев.


Многа букаф, ниасилил.


Игорь Шевченко   (2010-06-22 12:45:00) [4]


> Жду ваших комментариев.


Это мы ждем твоих комментариев


nobody   (2010-06-22 12:40:00) [5]

Вообщем, нашел старую разработку под Информикс
Переделал ее под Оракл.
Вот что получилось:
procedure TCustomConnectionManager.ExecuteThread(Thread: TThread);
 function OtherThreadsExists: Boolean;
 begin
   FCashLock.Enter;
   try
     Result := (FCash <> nil) and
       (FCash.Count > 1);
   finally
     FCashLock.Leave;
   end;
 end;
 function WaitExpired(Thread: TCashThread; Timeout: Cardinal): Boolean;
 begin
   FCashLock.Enter;
   try
     Thread.Waiting := True;
     Thread.Event.ResetEvent;
   finally
     FCashLock.Leave;
   end;
   try
     Result := Thread.Terminated or
       (Thread.Event.WaitFor(Timeout) <> wrSignaled) or
       Thread.Terminated;
   finally
     Thread.Waiting := False; // if Result is True or error
   end;
 end;
var
 CashThread: TCashThread;
 Connection: TObject;
 CashIndex: Integer;
 Task: TConnectionTask;
begin
 Connection := nil;
 CashThread := Thread as TCashThread;
 try
   repeat
     Task := nil;
     repeat
       if CashThread.CashSizeChanged and
         (CashThread.Series = nil) then
       begin
         FCashLock.Enter;
         try
           if FCash.Count > CashSize then
             CashThread.Terminate;
         finally
           FCashLock.Leave;
         end;
         if CashThread.Terminated then
           Break;
       end;
       FTaskLock.Enter;
       try
         Task := FFirst;
         if CashThread.Series = nil then
           while Task <> nil do
           begin
             if Task.Series = nil then
               Break;
             FCashLock.Enter;
             try
               CashIndex := FCash.Count;
               repeat
                 Dec(CashIndex);
               until (CashIndex < 0) or
                 (TCashThread(FCash[CashIndex]).Series = Task.Series);
             finally
               FCashLock.Leave;
             end;
             if CashIndex < 0 then
               Break;
             Task := Task.Next;
           end
         else
           while (Task <> nil) and
             (Task.Series <> CashThread.Series) do
             Task := Task.Next;
         if Task <> nil then
         begin
           if FFirst = Task then
           begin
             FFirst := Task.Next;
             if FFirst <> nil then
               FFirst.Prev := nil;
           end
           else
             Task.Prev.Next := Task.Next;
           if FLast = Task then
           begin
             FLast := Task.Prev;
             if FLast <> nil then
               FLast.Next := nil;
           end
           else
             Task.Next.Prev := Task.Prev;
           if Task is TSeriesStartTask then
             CashThread.Series := Task.Series
           else
             if Task is TSeriesEndTask then
               CashThread.Series := nil;
         end;
       finally
         FTaskLock.Leave;
       end;
       if Task <> nil then
       try
         Notify(Task, mnStart);
         try
           if Connection = nil then
           try
             Connection := CreateConnection;
           except
             FreeAndNil(Connection);
             raise;
           end;
           if Task is TSeriesStartTask then
             StartSeries(Connection, TSeriesStartTask(Task).Transaction)
           else
             if Task is TSeriesEndTask then
               EndSeries(Connection, TSeriesEndTask(Task).Action)
             else
               ExecuteTask(Connection, Task);
           Notify(Task, mnComplete);
         except
           on E: Exception do
             Notify(Task, mnError, E.Message);
         end;
       finally
         Task.Free;
         CashThread.Info.TaskExecuted;
       end;
     until CashThread.Terminated or
       ((Task = nil) and
       WaitExpired(CashThread, IdleTimeout));
   until CashThread.Terminated or
     OtherThreadsExists or
     WaitExpired(CashThread, ActivityTimeout);
 finally
   FreeAndNil(Connection);
 end;
end;

Жду ваших комментариев.


Игорь Шевченко   (2010-06-22 11:43:00) [6]

Petr V. Abramov ©   (22.06.10 11:32) [43]

Клиент сам по себе - thread safe, а как его инициализируют, это проблема инициализаторов


Petr V. Abramov   (2010-06-22 11:32:00) [7]


> Игорь Шевченко ©   (21.06.10 17:09) [28]
> клиент Oracle - thread safe.

когда инициализирован в соотв. режиме. У DOA это вынесено в какое-то не помню свойство OracleSession,  по умолчанию стоИт не safe.
Скорее всего, в данном случае проблема не только отсюда, но так, о птичках.


Игорь Шевченко   (2010-06-21 19:13:00) [8]


> где лочить контролы


TDataSet.DisableControls/EnableControls


nobody   (2010-06-21 18:16:00) [9]


> Гугл, Demos и книжки

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


Ega23   (2010-06-21 18:10:00) [10]


> вообщем туманно все и конкретных примеров с критической
> секцией никто не привел


Гугл, Demos и книжки - как, отменили?


nobody   (2010-06-21 18:09:00) [11]

кстати, убрал из метода TThreadControl.Execute
LockControl и UnLockControl и вроде перестало так залипать, но пока непонятно, где лочить контролы, во время выполнения потока ... или сделать это до выполнеия запроса, прямо перед созданием потока?... тогда нужен флаг, который будет сигнализировать завершение потока...
вообщем туманно все и конкретных примеров с критической секцией никто не привел... а как все хорошо начиналось... эх, пойду-нажрусь с горя!


Игорь Шевченко   (2010-06-21 17:38:00) [12]

Ega23 ©   (21.06.10 17:18) [32]


> С подключенными DataSource-ами?
> Ну тогда это хорошие компоненты.


Ты не путай божий дар с яичницей. Если у тебя в потоке происходит DataEvent и подключены визуальные компоненты, то все, что пишется в комментариях к TThread про Syncronize, остается в силе. А сами DataSet-ы в потоках вполне могут осуществлять свою функциональность. Например, их можно обходить.


Ega23   (2010-06-21 17:25:00) [13]


> ДОА тоже нормально работает с подключенными датасорсами
> в потоке...


Дык и обычный какой-нибудь TADODataSet может работать в потоке. С подключенными DataSource. Вопрос в том, как контролы себя вести будут. И насколько это целесообразно.


nobody   (2010-06-21 17:23:00) [14]


> Например.

Вот я бы тоже и хотел посмотреть на  пример использования этой схемы работы с потоком...


nobody   (2010-06-21 17:21:00) [15]


> С подключенными DataSource-ами?
> Ну тогда это хорошие компоненты.

ДОА тоже нормально работает с подключенными датасорсами в потоке...


Ega23   (2010-06-21 17:20:00) [16]


> а соответствующие контроллы блокировать, пока не будет получено
> сообщение
> WM_THREAD_DONE?


Например.


nobody   (2010-06-21 17:19:00) [17]

//DoSomeWork;
- здесь выполнять открытие датасета? а что по поводу memtable? и критических секций по бокам?


Ega23   (2010-06-21 17:18:00) [18]


> а наши компоненты доступа к Oracle вполне спокойно относятся
> к передаче их в поток (ну и манипуляций с ними в потоке)


С подключенными DataSource-ами?
Ну тогда это хорошие компоненты.


nobody   (2010-06-21 17:18:00) [19]


> Ega23 ©   (21.06.10 17:14) [30]

а соответствующие контроллы блокировать, пока не будет получено сообщение
WM_THREAD_DONE?


Ega23   (2010-06-21 17:14:00) [20]


> Покажите кто-нить кусок кода из готового проекта, плиз!


 TMyThread = class (TThread)
 private
   FWND: HWND;
   FID: Integer;
   function ReportStartExecution: Boolean;
 protected
   procedure Execute; override;
 public
   constructor Create(aID: Integer; Wnd: HWND);
   procedure DoTerminate; override;
 end;

constructor TMyThread.Create(aTaskID: Integer; Wnd: HWND);
begin
 inherited Create(True);
 FWND := Wnd;
 FID := aID;
 FreeOnTerminate := True;
end;

function TMyThread.ReportStartExecution: Boolean;
begin
 Result := SendMessage(FWND, WM_THREAD_START,
   Integer(Self), FID) = WM_RESULT_OK;
end;

procedure TMyThread.DoTerminate;
begin
 PostMessage(FWND, WM_THREAD_DONE, Integer(Self), TaskID);
end;

procedure TMyThread.Execute;
begin
 try
   ReportStartExecution;

   //DoSomeWork;

 except
    //////
 end;
end;


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо