Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Помогите "временно" заблокировать процедуру 
:(
    Опции темы
oleg153
Дата 4.5.2009, 19:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 34
Регистрация: 1.3.2007

Репутация: нет
Всего: нет



Есть 3 приложения :
- Клиент (1)
- Сервер-Клиент (2)
- Сервер (3)

Основное - (2) . Описаны две процедуры которые работают с MSSQL через ADO. Процедура-2 вызывается Клиентом(1) ,  Процедура-1 вызывается  Сервер-Клиентом (2).
Обе процедуры исполняются на Сервер-Клиенте.
В процесе исполнения Процедуры-1 , Сервер (2) - обращается к внешнему Серверу(3) .

Проблемма в том что НИКАК ни через Критич. Секции, Ни через Мьютексы не могу заставить  процедуру-2, ждать пока не отработается процедура-1. 
Как только я вызываю метод реализованый на Сервере (3) вся защита слетает и начинает отрабатываться процедура-1 запущеная Клиентом.

Код

  private
    { Private declarations }
    CritSec:TRTLCriticalSection;
    DServ:Variant;
    hMutex   : THandle;
  public
    { Public declarations }
    procedure LockForm;
    procedure UnlockForm;
    procedure SetData1;
    procedure SetData2;
    procedure SetPause(MS:integer);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
procedure TForm1.SetPause(MS:integer);
begin
 Sleep(MS)
end;

procedure TForm1.SetData1;
begin
 if WaitForSingleObject(hMutex,INFINITE) = WAIT_OBJECT_0  then
 try
  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;
         Next;
        end;
     end;
   end; //with
 finally
  ReleaseMutex(hMutex);
 end;
end;

procedure TForm1.SetData2;
begin
 if WaitForSingleObject(hMutex,INFINITE) = WAIT_OBJECT_0  then
 try
  with ADOQuery1 do
   begin
    Close;
    Open;
    if RecordCount >0 then
     begin
      First;
      Edit;
      FieldByName('lockState').AsString:= 'unlock';
      Post;
     end;
   end; //with
 finally
  ReleaseMutex(hMutex);
 end;
end;




procedure TForm1.Button1Click(Sender: TObject);
begin
// try
//  LockForm;
  SetData1;
// finally
//  UnlockForm;
// end;
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);

 hMutex   := CreateMutex(nil,false,'TerminalMutex');
 if hMutex = 0 then  RaiseLastWin32Error;

 memo1.Clear;

 end;

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

 CloseHandle(hMutex);
end;

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

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

В общем как доходит Процедура-1 до  DServ.Test1(7000);

Вся защита срывается и начинает отрабатываться  procedure TForm1.SetData2 которая в этот момент ждет исполнения вызваная Клиентом (1).

Код

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





Мне НУЖНО чтоб Процедура-1 отработалась до конца и только потом запустилась ждущая Процедура-2

Подскажите КАК это сделать. Бьюсь уже вторые сутки....

PM MAIL   Вверх
MetalFan
Дата 5.5.2009, 08:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 62
Всего: 128



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


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
CodeMonkey
Дата 5.5.2009, 09:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 38
Всего: 89



Может и глупость скажу, но...  у вас процедура-1 и процедура-2 выполняются в разных потоках? Добавьте логгинг GetCurrentThreadId.
Если в одинаковых, то, скорее всего, ситуация выглядит как-то так: запускается процедура-1, берёт блокировку, где-то внутри себя вызывает Application.ProcessMessages (или аналог) - в этот момент запускается сидящая в очереди процедура-2, она работает, поскольку текущий поток уже владеет блокиовкой, процедура-2 завершается, затем заканчивается процедура-1 и отпускает блок.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
oleg153
Дата 5.5.2009, 13:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 34
Регистрация: 1.3.2007

Репутация: нет
Всего: нет



Спасибо. Кое что понял

Я проверил - по        Memo1.Lines.Add(inttostr(GetCurrentThreadId()); 
получается что поток один. 

Я из того что читал понял что VCL (основной поток) и поток COM - разные, даже если сервер создан как STA. Но похоже я ошибся.

Значит все варианты блокировки с использованием секций и мьютексов не пройдут. Или нужно создавать отдельные потоки

Но почему запускается Процедура-2 ? Ведь вроде смысл одного потока - ждать окончания 1-ой процедуры ?

И что делать если НЕ разделять процедуры по разным потокам ? Как не позволить запускаться  

PM MAIL   Вверх
CodeMonkey
Дата 5.5.2009, 13:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 38
Всего: 89



Цитата
Но почему запускается Процедура-2 ?

Если вы привели полный код, то вот это у вас кто: DServ.Test1?
Ещё ShowMessage содержит цикл Application.ProcessMessages (если это действительно причина).


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
oleg153
Дата 5.5.2009, 14:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 34
Регистрация: 1.3.2007

Репутация: нет
Всего: нет



Код

 //Подключение к серверу.
  DServ := CreateOLEObject('DataServer.OfflineServer1');


DServ - соответственно Сервер-3. Еще один сом-сервер также реализованый как STA (однопотоковый) , который производит обработку переданых ему в процедуре SetData1 - данных.

В Данном примере я на сервере-3 просто организовал задержку и передаю время задержки. Это для тестирования. В реали я передаю данные которые обрабатываются 0.5-5 сек и возвращают результат обработки. Возврат не стал делать так как его наличие не влияет на результат, все равно в потоке после вызова DServ.Test1 начинает работать Процедура-2.
Т.е. в основном потоке очередь от Процедуры-1 передается на П-2 хотя П-1 не отработалась до конца.

К сожалению [B][Ещё ShowMessage содержит цикл Application.ProcessMessages (если это действительно причина)./B] - это мне не понятно. Если можно поясните.
PM MAIL   Вверх
CodeMonkey
Дата 5.5.2009, 15:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 38
Всего: 89



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


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
Palladin
Дата 5.5.2009, 20:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 932
Регистрация: 15.5.2007
Где: Беларусь г.Гомель

Репутация: 3
Всего: 17



Мдя, ну на крайняк:
Создаешь переменную, обнуляешь её, когда заканчивается первая процедура присваеваешь переменной, ну к примеру значение '1', а весь код второй процедуры заключаешь в 
Код

if(a=1)then
 begin
  весь код второй процедуры
 end;


 smile

Добавлено через 3 минуты и 41 секунду
Не прочитал все, поэтому сверху чушь.
Однако, вот ты передаешь значения в первой процедуре, во второй попробуй проверять, ну мол передалось ли последнее значение первой процедуры, если да то выполняем вторую процедуру, если нет...
Получается тоже if(a=1) только вместо а проверяй мол ввелось ли или передалось ли чтонить...


--------------------
Глуп тот кто полагается на истину авторитета, а не на авторитет истины
[color=red]KAV&KIS==Evil[/color]
PM MAIL   Вверх
MetalFan
Дата 6.5.2009, 07:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 62
Всего: 128



Цитата(oleg153 @  5.5.2009,  14:01 Найти цитируемый пост)
Еще один сом-сервер также реализованый как STA (однопотоковый)


Цитата(oleg153 @  5.5.2009,  14:01 Найти цитируемый пост)
К сожалению [B][Ещё ShowMessage содержит цикл Application.ProcessMessages (если это действительно причина)./B] - это мне не понятно.

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


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
oleg153
Дата 6.5.2009, 11:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 34
Регистрация: 1.3.2007

Репутация: нет
Всего: нет



В общем вроде понял.

У меня был Сервер-2 однопотоковый. Соответственно ни секции ни мьютексы не работали. Сом-методы вызывались в основном, и захват Крит.секции этим потоком позволял выполнять как процедуры вызваные Сервером, так и через СОМ.

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

В общем , чтоб не городить флаги, придется делать многопотоковый сервер и просто внимательно следить за обращением к VCL-компонентам.  Обращаться к ним только из основного потока,
когда он владеет Крит.секцией.

Пока на первый взгляд так должно работать. В вышеприведенном коде вроде работает.


PM MAIL   Вверх
CodeMonkey
Дата 6.5.2009, 13:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 38
Всего: 89



Ну, для обращения к главному потоку из любого вторичного есть Synchronize (также и в статическом варианте), либо удобная оболочка для него EnterMainThread/LeaveMainThread из AsyncCalls.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
oleg153
Дата 6.5.2009, 15:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 34
Регистрация: 1.3.2007

Репутация: нет
Всего: нет



Если можно, проясните, сам пока не понял. 

Есть Основной поток Сервера  и COM-поток созданный Сервером

Для исключения доступа к процедуре описаной в главной форме использую Крит. секцию.

СОМ-поток захватывает секцию и работает с Таблицами (MSSQL) через ADO.

Если в момент работы когда Крит.сек. захвачена Основной поток пытается запустить процедуру, он натыкается на блокировку через Крит.секс. и становится в ожидание.

И вот если в этот момент активный СОМ-поток пытается что либо сделать с экранными компонентами (Memo, DBGrid ) - тогда все умирает. Совсем. Тупик.

Понимаю что это из-за блокировки основного потока Критической секцией.

Но поможет ли здесь Synchronize ? Ведь основной поток заблокирован на попытке EnterCriticalSection(CS); 

Подскажите, так как с потоками только разбираюсь и боюсь напортачить.
PM MAIL   Вверх
CodeMonkey
Дата 6.5.2009, 16:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 38
Всего: 89



Цитата
Если в момент работы когда Крит.сек. захвачена Основной поток пытается запустить процедуру, он натыкается на блокировку через Крит.секс. и становится в ожидание.

Мне просто показалось, что обе процедуры запускаются из вторичных потоков. А так, вы, конечно, правы - у вас будет dead-lock - два потока будут ждать друг-друга.

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

Если пойдёте таким путём, то к вашим услугам Synchronize.
Если же нет - то тут только отправка сообщений. Да и то, сообщение не будет обработано, пока главный поток блокирован. Так что, ситуация с dead-lock-ом может даже и повториться, если вы используете SendMessage.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
oleg153
Дата 6.5.2009, 16:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 34
Регистрация: 1.3.2007

Репутация: нет
Всего: нет



Да. Спасибо.

Я Тоже прихожу к выводу что придется запускать в отдельном, не COM потоке.  Теперь осталось внимательно разобратся с потоками.
PM MAIL   Вверх
oleg153
Дата 6.5.2009, 17:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 34
Регистрация: 1.3.2007

Репутация: нет
Всего: нет



Пока еще не понял как совместить Synchronize и ADO

Допустим в потоке нужно выполнить код :

Код

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

Здесь ADOQuery через TDataSource отображает в таблице DBGrid результаты. Причем динамически. 
Это можно увязать с Synchronize ?
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0929 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.