Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: ActiveX/СОМ/CORBA > Как избежать одновременного доступа к процедуре


Автор: oleg153 30.4.2009, 19:25
Приложение работает с таблицей SQL - (Таб-1)

По Таймеру :
По таблице делаю Выборку и для выбраных записей выполняю расчеты (бывает долго, 2-5 сек) зависимости от результата меняю одно из полей записи. 
Возврат результата занимает от милисекунд до 2-5 секунд.

При этом для данного приложения я сделал (ActiveX (exe) сервер) несколько методов, которые
также используют теже процедуры работы с базой которые описаны в основной (VCL) форме.

Чтоб избежать одновременного доступа к процедуре по событию Таймера (VCL-поток) и вызова этой процедуры (или другой, которая тоже работает с Таб-1) внешним приложением через Метод, я использовал Критическую Секцию и выполняю процедуры как через метод описаный в библиотеке, так и в основной форме по таймеру только отработав вход -выход в Критическую секцию.

Думал это поможет , НО ВСЕ РАВНО ПРОИСХОДИТ ОДНОВРЕМЕННЫЙ ДОСТУП К ДАННЫМ , значит критическая секция или не действует или что-то я не понимаю. 


Подскажите КАК сделать так чтоб при наличии нескольких процедур, которые могут вызываться в основной форме и извне, не происходил одновременный запуск , что рушит базу (вернее возникает сбой)

Автор: Rrader 1.5.2009, 07:57
Цитата(oleg153 @  1.5.2009,  01:25 Найти цитируемый пост)
значит критическая секция или не действует или что-то я не понимаю. 

Скорее второе. Можете показать Ваш примерный код работы с секцией?

Автор: oleg153 4.5.2009, 15:03
В основной форме

Код

  private
    { Private declarations }
    CritSec:TRTLCriticalSection;
    DServ:Variant;
  public
    { Public declarations }
    procedure LockForm;
    procedure UnlockForm;
    procedure SetData1;
    procedure SetData2;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.SetData1;
begin
with ADOQuery1 do
 begin
  Close;
  Open;
  if RecordCount >0 then
   begin
    First;
    while not Eof do
      begin
       Edit;
       FieldByName('lockState').AsString:= 'lock';
       Post;
        // для тестирования.  Внешняя задержка
       if VarType(DServ) = varDispatch then
        begin
         DServ.Test1(7000);
        end
        else
        begin
         ShowMessage('Нет подключенного сервера');
        end;
       //Sleep(7000); // для тестирования.  Внутренняя задержка
       Next;
      end;
   end;
 end; //with
end;

procedure TForm1.SetData2;
begin
with ADOQuery1 do
 begin
  Close;
  Open;
  if RecordCount >0 then
   begin
    First;
    Edit;
    FieldByName('lockState').AsString:= 'unlock';
    Post;
   end;
 end; //with
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Label1.Color:=clRed;
 try
  LockForm;
  SetData1;
 finally
  UnlockForm;
 end;
Label1.Color:=clGreen;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 //Подключение к серверу.
  DServ := CreateOLEObject('DataServer.OfflineServer1');
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
 //Отключение от сервера.
 if VarType(DServ) = varDispatch then
  begin
   DServ := Unassigned;
  end
  else
  begin
   ShowMessage('Нет подключенного сервера');
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 try
  {Открываем сеанс связи с б.д.}
  ADOConnection1.Open;
 except
  ShowMessage('Не удалось установить связь с б.д., сервер не доступен.');
 end;
 {инициализируем Критическую Секцию}
 InitializeCriticalSection(CritSec);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 {Закрываем сеанс связи с базой данных}
  ADOConnection1.Close;
 {Закрываем Критическую секцию}
  DeleteCriticalSection(CritSec);
end;

{Захват потоком критической секции}
procedure TForm1.LockForm;
 begin
  EnterCriticalSection(CritSec);
 end;

 {Освобождение потоком критической секции}
procedure TForm1.UnlockForm;
 begin
  LeaveCriticalSection(CritSec);
 end;


Смоделировал ошибку.

Если procedure: SetData1 вызывается из Основной формы, а SetData2 из Клиентского приложения, тогда :
 - Если пауза ( Sleep() ) отрабатывается в Основной форме - тогда при попытке исполнить Клиентом SetData2 - он не исполняется, ждет отработки SetData1.
 - Если пауза исполняется на ВНЕШНЕМ сом-сервере к которому подключаю Основной, и на этом 2-ом сервере отрабатывается пауза (это аналок действий которые на нем отрабатываются в реали и требуют время) - тогда по неясным пока мне причинам Защита через Критическую секцию работать перестает, и можно исполнить SetData2 ДО окончания исполнения SetData1.

При этом SetData1 и SetData2 работают с одним набором данных и НЕЛЬЗЯ чтоб SetData2 мог исполниться до ПОЛНОГО исполнения SetData1

Добавлено через 2 минуты и 43 секунды
Конечно при описании метода который использует SetData2 я также использую Крит. секцию.

Код

procedure Ttest15.KlientSetData(const ScriptCode: WideString);
begin
 try
  Form1.LockForm;
  Form1.SetData2;
 finally
  Form1.UnlockForm;
 end;
end;


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)