Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 07.09.2017, 17:51   #1
Denis_2017
Новичок
Джуниор
 
Регистрация: 07.09.2017
Сообщений: 5
По умолчанию Потоки и их синхронизация

Здравствуйте, помогите разобраться с потоками.
Есть MID приложение, которое работает с удаленной базой Firebird. У меня проблемы с синхронизацией с динамически создаваемой формой.
На главной форме по нажатии на кнопку button1 :
Код:
procedure TFmMain.SP_USERS_NClick(Sender: TObject);
begin
  // Создаю дочернюю форму
  Application.CreateForm(TFmUsers, FmUsers);
  // Показываю дочернюю форму
  FmUsers.Show;
  // Создаю критическую секцию`
  G_GOUSERS := TCriticalSection.Create;
  //Создаю и запускаю поток
  with ThGOUSERS.Create(True) do
    begin
      Priority := tpNormal;
      FreeOnTerminate := True;
      Resume;
    end;
end;
В потоке:
Код:
procedure ThGOUSERS.Execute;
begin
  try
    G_GOUSERS.enter;
  //Выключаю все котролы на форме(кнопки, edit, combobox и т.п.)
  Synchronize(DisCtr);
   //Проверяю соединение с БД
  if ThDBCONNECTU.G_DBCONNECT(DB,T,ERRMES) < 0 then
        begin
          Synchronize(SetErrMes);
          Exit;
        end;
//Запрашиваю данные из таблицы
//……Здесь много кода
//Запрашиваю данные из таблицы  конец
//Включаю все котролы на форме(кнопки, edit, combobox и т.п.)
  Synchronize(EnCtr)
  Finally
     G_GOUSERS.leave;
  end;
end;
Все хорошо работает, но если закрыть форму во время выполнения потока, то получаю Exception в связи с тем, что процедура Synchronize(EnCtr) не может отработать – формы больше не существует, по закрытию дочернего окна я его уничтожаю.
procedure TFmUsers.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
Подскажите как правильно проверять в Synchronize существование обновляемого объекта, чтобы избежать Exception.
P.S. Я привел сокращенный пример потока с 2 –мя процедурами Synchronize для лучшего понимаю, у меня в потоке синхронизаций 10-12 и больше…
Denis_2017 вне форума Ответить с цитированием
Старый 07.09.2017, 18:43   #2
Sciv
Старожил
 
Аватар для Sciv
 
Регистрация: 16.05.2012
Сообщений: 3,211
По умолчанию

Если на каждую динамическую форму создаётся свой поток по нажатию на button1, то можно в Button1.OnClick запоминать поток, а в OnClose формы делать ему terminate.
Начал решать проблему с помощью регулярных выражений. Теперь решаю две проблемы...
Sciv вне форума Ответить с цитированием
Старый 07.09.2017, 18:52   #3
Denis_2017
Новичок
Джуниор
 
Регистрация: 07.09.2017
Сообщений: 5
По умолчанию

Цитата:
Сообщение от Sciv Посмотреть сообщение
Если на каждую динамическую форму создаётся свой поток по нажатию на button1, то можно в Button1.OnClick запоминать поток, а в OnClose формы делать ему terminate.
Т.е. поток сделать глобальной переменной?
Denis_2017 вне форума Ответить с цитированием
Старый 07.09.2017, 18:55   #4
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

и для чего тут TCriticalSection если один ходок в нее ходит?
подозреваю что ходоков много, но ты для каждого свой TCriticalSection лепишь...
кроме того потенциальный дедлок - Synchronize тоже синхронизатор и если внутри Synchronize (работа в основном потоке) еще раз сделать enter в ту же критическую секцию - зависнет нахрен т.к. уже войдено в другом потоке
глобальной? забудь это слово... делай в поле создаваемой формы хоть в varом public

Код:
TFmUsers
...
public
  thread:TThread;
Не стесняемся, плюсуем!

Последний раз редактировалось Slym; 07.09.2017 в 19:01.
Slym вне форума Ответить с цитированием
Старый 07.09.2017, 18:56   #5
Denis_2017
Новичок
Джуниор
 
Регистрация: 07.09.2017
Сообщений: 5
По умолчанию

Цитата:
Сообщение от Slym Посмотреть сообщение
и для чего тут TCriticalSection если один ходок в нее ходит?
подозреваю что ходоков много, но ты для каждого свой TCriticalSection лепишь...
На Button1 могут нажать 685 раз
Denis_2017 вне форума Ответить с цитированием
Старый 07.09.2017, 21:10   #6
7in
(aka Jin X) !RTFM!
Форумчанин
 
Аватар для 7in
 
Регистрация: 14.12.2014
Сообщений: 295
По умолчанию

Цитата:
Сообщение от Slym Посмотреть сообщение
подозреваю что ходоков много, но ты для каждого свой TCriticalSection лепишь...
Это да. Его нужно создавать не в обработчике сообщения каждый раз (тем более, объект не освобождается в итоге), а в TFmMain.OnCreate основной формы.

Цитата:
Сообщение от Slym Посмотреть сообщение
кроме того потенциальный дедлок - Synchronize тоже синхронизатор и если внутри Synchronize (работа в основном потоке) еще раз сделать enter в ту же критическую секцию - зависнет нахрен т.к. уже войдено в другом потоке
глобальной? забудь это слово... делай в поле создаваемой формы хоть в varом public
Откуда предположение, что в основной форме будет вход в критическую секцию?

У меня такие вопросы:
1. Зачем Synchronize(DisCtr) и Synchronize(EnCtr) делать в критической секции? И процедуры DisCtr и EnCtr - это методы какого класса? Откуда они понимают, на какой форме нужно отключать контролы? Откуда они берут адрес FmUsers?
2. Почему нельзя сделать один Enter+Synchronize(InitForm)+Leave и в этом InitForm сделать всё, что нужно? Каждый Synchronize порождает дополнительные задержки.

А основную проблему можно решить вот так:
Код:
procedure TFmMain.FormCreate(Sender: TObject);
begin
  // Создаю критическую секцию
  G_GOUSERS := TCriticalSection.Create;
end;

procedure TFmMain.SP_USERS_NClick(Sender: TObject);
begin
  //Создаю и запускаю поток
  with ThGOUSERS.Create(True) do
    begin
      // Создаю дочернюю форму
      Application.CreateForm(TFmUsers, FmUsers);  // FmUsers должен быть определён ВНУТРИ ThGOUSERS
      // ....Здесь отключаем все контролы формы....
      FmUsers.AllowClose := False;  // Запрещаем закрытие формы (на всякий случай... вдруг юзер успеет закрыть форму до синхронизации) :)))
      // Показываю дочернюю форму
      FmUsers.Show;
//      Priority := tpNormal;  // Смысл? Он и так будет Normal
      FreeOnTerminate := True;
      Resume;
    end;
end;

procedure ThGOUSERS.Execute;
begin
  try
     G_GOUSERS.enter;
  //Выключаю все котролы на форме(кнопки, edit, combobox и т.п.)
     Synchronize(FmUsers.InitForm);  // InitForm - это метод TFmUsers... ну или метод ThGOUSERS, тогда без "FmUsers."
  Finally
     FmUsers.AllowClose := True;
     G_GOUSERS.leave;
  end;
end;

procedure TFmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := AllowClose;
end;
Код:
procedure TFmUsers.InitForm;
begin
  // тут ведётся работа с базой и в конце влючаются контролы
end;
Типа такого...
Делаю лабы на Asm/Delphi/C++/Python/VBA(Excel): asmlabs.ru

Последний раз редактировалось 7in; 07.09.2017 в 21:30.
7in вне форума Ответить с цитированием
Старый 07.09.2017, 21:16   #7
Denis_2017
Новичок
Джуниор
 
Регистрация: 07.09.2017
Сообщений: 5
По умолчанию

Цитата:
FmUsers.AllowClose := False; // Запрещаем закрытие формы
FmUsers.WannaClose := False; // Не было попыток закрыть форму
Это конечно выход, но что если соединение не стабильно, пользователю по-любому нужно дождаться завершение потока?
Denis_2017 вне форума Ответить с цитированием
Старый 07.09.2017, 21:25   #8
7in
(aka Jin X) !RTFM!
Форумчанин
 
Аватар для 7in
 
Регистрация: 14.12.2014
Сообщений: 295
По умолчанию

Кон писал "на лету", без проверки.... немного поменял, посмотри заново
Без WannaClose. Всё равно форма подвиснет, пока идёт соединение с базой...

Цитата:
Сообщение от 7in Посмотреть сообщение
Откуда они понимают, на какой форме нужно отключать контролы?
А если контролы отключаются на основной форме (а не на создаваемой форме), тогда дополнительный поток вообще не нужен.
Это всё делается ради того, что если юзер нажал на кнопку 5 раз подряд, то ему должно открыться 5 окон, а не одно (пока идёт инициализация и только после этого можно нажать ещё раз на кнопку, чтобы она сработала)...
Делаю лабы на Asm/Delphi/C++/Python/VBA(Excel): asmlabs.ru
7in вне форума Ответить с цитированием
Старый 07.09.2017, 21:26   #9
7in
(aka Jin X) !RTFM!
Форумчанин
 
Аватар для 7in
 
Регистрация: 14.12.2014
Сообщений: 295
По умолчанию

Цитата:
Сообщение от Denis_2017 Посмотреть сообщение
Это конечно выход, но что если соединение не стабильно, пользователю по-любому нужно дождаться завершение потока?
Ну а как ещё?
Скажи как надо, от этого и будем плясать...
Делаю лабы на Asm/Delphi/C++/Python/VBA(Excel): asmlabs.ru
7in вне форума Ответить с цитированием
Старый 07.09.2017, 21:28   #10
Denis_2017
Новичок
Джуниор
 
Регистрация: 07.09.2017
Сообщений: 5
По умолчанию

Цитата:
Сообщение от 7in Посмотреть сообщение
Кон писал "на лету", без проверки.... немного поменял, посмотри заново
Без WannaClose. Всё равно форма подвиснет, пока идёт соединение с базой...

А если контролы отключаются на основной форме (а не на создаваемой форме), тогда дополнительный поток вообще не нужен.
Это всё делается ради того, что если юзер нажал на кнопку 5 раз подряд, то ему должно открыться 5 окон, а не одно (пока идёт инициализация и только после этого можно нажать ещё раз на кнопку, чтобы она сработала)...
Примерно понял, буду пробовать. Спасибо.
Denis_2017 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Потоки, синхронизация stalker1995s Общие вопросы Delphi 6 09.01.2014 17:03
Потоки. Закрываются все потоки при ошибке в одном. Son Общие вопросы Delphi 11 01.11.2013 09:32
Потоки, синхронизация, простой denrubun Общие вопросы C/C++ 11 29.06.2013 13:37
синхронизация s.e.r.g. C++ Builder 10 11.02.2013 22:33
синхронизация perun47 Microsoft Office Excel 0 31.01.2012 22:35