powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / И опять про потоки и про формы
25 сообщений из 29, страница 1 из 2
И опять про потоки и про формы
    #39839698
Basketbol
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день!
Прочитал много всего про потоки, в том числе и на этом форуме.
Но не могу понять как правильно реализовать мою задачу.
Максимально упрощенная задача:
Нужно выполнять параллельно несколько потоков, которые меняют свойство progress компонента-бегунка TGaude.
Как я пытаюсь сделать:
Есть форма с TGaude на нем.
Есть поток:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
type
  TThreadMyForm = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  public
    FMyForm : TMyForm; //Ссылка на форму
  end;



Я создаю поток suspended = true, после создания присваиваю его публичному свойству FMyForm ссылку на только что созданную форму, и запускаю на выполнение:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
    myForm := TMyForm.Create(Application);

    threadMyForm := TThreadMyForm.create(true);
    with threadMyForm do
    begin
      freeOnTerminate := true;
      FWebForm := webForm;
      FMyForm := myForm;
      Resume;
    end;



В самой форме описана процедура изменения ползунка. И этот метод я вызываю в цикле Execute потока.

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
procedure TMyForm.actionChangeGaude(milisek : integer);
var
  i: Integer;
begin
  gaude.Progress := 0;
  gaude.MaxValue := milisek;

  for i := 0 to milisek do
  begin
    sleep(100);
    gaMain.Progress := i;
    Application.ProcessMessages;
  end;
end;



Этот метод не знает что он вызван в Execute потока.


Я не понимаю как нужно сделать возможность безопасного закрытия формы пользователем в момент выполнения потока.

Когда я просто закрываю форму - поток остается работать, и пытается что то менять на уже уничтоженной форме. (Форма уничтожается в момент закрытия).

Т.е. конечно же нужно перед закрытием формы уничтожить поток, который на этой форме что то делает.
Следовательно - форма должна знать о потоке.
Следовательно - после создания потока я указываю его как значение поля формы FMyThread:
Код: pascal
1.
   myForm.FThread := myThread as TThread;



И в onclose формы делать так:

Код: pascal
1.
2.
3.
    FThread.Terminate;
    FThread.WaitFor;
    FThread.Free;



Но эксперименты показывают что это все неправильно, ибо вылазит ошибка на WaitFor : "Неверный дескриптор"

Ну и то что поток вызывает метод формы, который описан в самой форме, и который не знает что его вызвал поток - это кмк тоже неправильно.

Какая должна быть правильная архитектура такой задачи?
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839699
Basketbol
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Может генерировать события?
Пользователь вызывает событие closeQuery у формы.
В closeQuery мы пишем потоку terminate.
И после создания потока мы подписываемся на событие onTerminate потока.
И после возникновения события устанавливаем переменную FCanClose в true
Как то так что ли...
...
Короче - каша в голове.
Не хватает опыта работы с потоками...
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839712
Basketbol
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Нашел ошибку: после уничтожения потока нужно полю формы FThread (то которое ссылается на управляющий поток) присваивать nil.
...
Но все равно - архитектура какая то люто неправильная...
Все на все ссылается....
Никакой абстракции...
..
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839714
Basketbol
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Пришел к тому, что действия которые что то делают с формой, должны быть описаны в классе потока.
Также как и какие то длительные действия - паузы, ожидания чего-либо.
Ибо в классе самого потока я смогу анализировать поле terminated экземпляра потока, и вовремя прекращать.

Т.е. создаем форму.
Создаем поток.
Полю FMyForm потока присваиваем myForm
И наоборот: полю FMyThread формы присваиваем ссылку на поток.

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

Ну и после уничтожения потока полю формы FmyThread присваиваем nil.

Не красиво, но работать будет.
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839717
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BasketbolПрочитал много всего про потоки, в том числе и на этом форуме.
Вы, судя по всему, даже комментарий, который среда создаёт для нового потока, не прочитали.
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
{
  Important: Methods and properties of objects in visual components can only be
  used in a method called using Synchronize, for example,

      Synchronize(UpdateCaption);

  and UpdateCaption could look like,

    procedure ввв.UpdateCaption;
    begin
      Form1.Caption := 'Updated in a thread';
    end;

    or

    Synchronize(
      procedure
      begin
        Form1.Caption := 'Updated in thread via an anonymous method'
      end
      )
    );

  where an anonymous method is passed.
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839718
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basketbol,

Не говоря уже о том, что вы вообще не понимаете что вы делаете:
Код: pascal
1.
2.
3.
4.
5.
  freeOnTerminate := true;
  ....
  FThread.Terminate;
  FThread.WaitFor;  <-- К этому моменту уже может быть вызван FThread.Free (см. выше), что вы ждёте от этого вызова?.. 
  FThread.Free;
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839720
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
может применить компоненту, которая инкапсулирует всю работу с потоком внутри?
их есть несколько разных.
то, что сейчас сделано, конечно, можно в сотый раз поругать, но не знаю надо ли )
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839722
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alekcvpBasketbol,

Не говоря уже о том, что вы вообще не понимаете что вы делаете:
Код: pascal
1.
2.
3.
4.
5.
  freeOnTerminate := true;
  ....
  FThread.Terminate;
  FThread.WaitFor;  <-- К этому моменту уже может быть вызван FThread.Free (см. выше), что вы ждёте от этого вызова?.. 
  FThread.Free;

Не говоря о том, что Terminate и WaitFor будут вызваны в деструкторе (если он вызовется внутри Free)
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839738
Фотография X-Cite
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BasketbolНо не могу понять как правильно реализовать мою задачу.
Нужно выполнять параллельно несколько потоков, которые меняют свойство progress компонента-бегунка TGaude.


Какая задача на самом деле? Вы сейчас описали не задачу, а реализацию...
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839757
Basketbol
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
YuRockalekcvpBasketbol,

Не говоря уже о том, что вы вообще не понимаете что вы делаете:
Код: pascal
1.
2.
3.
4.
5.
  freeOnTerminate := true;
  ....
  FThread.Terminate;
  FThread.WaitFor;  <-- К этому моменту уже может быть вызван FThread.Free (см. выше), что вы ждёте от этого вызова?.. 
  FThread.Free;

Не говоря о том, что Terminate и WaitFor будут вызваны в деструкторе (если он вызовется внутри Free)

Что waitFor противоречит freeOnTerminate = true - я прекрасно знаю. И что данный форум не позволяет редактировать посты - тоже. FreeOnTerminate я делаю false при создании, поэтому все норм с этим.
И что менять состояние vcl компонентов синхронайзом - я тоже знаю и делаю.
Вопрос был именно про архитектуру.
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839767
Basketbol
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
X-CiteBasketbolНо не могу понять как правильно реализовать мою задачу.
Нужно выполнять параллельно несколько потоков, которые меняют свойство progress компонента-бегунка TGaude.


Какая задача на самом деле? Вы сейчас описали не задачу, а реализацию...

Есть некие последовательности действий: сделать то то, подождать выполнения какого то условия, сделать паузу столько то секунд и другие. Некоторые из этих действий затрагивают компоненты VCL.
Я запускаю n потоков и для каждого потока я создаю n форм. Т.е. каждый поток работает со своей формой и не знает о существовании других потоков и форм. И на текущий момент нет никаких разделямых ресурсов. Соответственно мне не нужно делать никаких критических секций и семафоров.
Но должна быть возможность закрытия форм пользователем в любой момент. В этом и была проблема.
Соответственно, чтобы сделать это безопасно - я сначала должен дождаться полного уничтожения потока.

В итоге к чему я пришел:
1. Поток видит форму через свое поле. Поток должен знать о своей форме, ведь он с ней выполняет какие то действия.
2. Форма видит поток также через свое поле. Форма должна знать об управляющем потоке, ведь она должна его уничтожить во время своего закрытия.
3. Все действия с формой нужно реализовывать в классе потока. Во первых чтобы можно было использовать синхронайз, во вторых - чтобы постоянно анализировать terminate, дабы прекращать всяческие циклические операции когда форму закроет пользователь.
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839774
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
[quot Basketbol]X-CiteВ итоге к чему я пришел:
1. Поток видит форму через свое поле. Поток должен знать о своей форме, ведь он с ней выполняет какие то действия.
2. Форма видит поток также через свое поле. Форма должна знать об управляющем потоке, ведь она должна его уничтожить во время своего закрытия.
3. Все действия с формой нужно реализовывать в классе потока. Во первых чтобы можно было использовать синхронайз, во вторых - чтобы постоянно анализировать terminate, дабы прекращать всяческие циклические операции когда форму закроет пользователь.В целом логика правильная. Как я понимаю реализация хромает и много повторяющего кода выходит?

Можно и метод формы передать потоку на выполнение, вариантов много, вот пункт 3 уже и не такой обязательный выходит
т.е. изначальная кривая архитектура RTL это не повод для уныния, напишите свою - дельфи пока ещё системный язык
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839776
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Недавно обсуждали нечто подобное: 21916011
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839798
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BasketbolЯ запускаю n потоков и для каждого потока я создаю n форм. Т.е. каждый поток работает со своей формой и не знает о существовании других потоков и форм.
Тогда какие проблемы? Описываешь экземпляр доп.потока в форме, которую будешь создавать. В потоке изменяешь gaude этой формы через synchronize/queue. Потом вызываешь эту форму столько раз, сколько нужно. И все.
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839825
Василий 2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BasketbolВ итоге к чему я пришел:
1. Поток видит форму через свое поле. Поток должен знать о своей форме, ведь он с ней выполняет какие то действия.
2. Форма видит поток также через свое поле. Форма должна знать об управляющем потоке, ведь она должна его уничтожить во время своего закрытия.
3. Все действия с формой нужно реализовывать в классе потока. Во первых чтобы можно было использовать синхронайз, во вторых - чтобы постоянно анализировать terminate, дабы прекращать всяческие циклические операции когда форму закроет пользователь.
Есть вероятность дедлока, когда форма из OnClose вызовет WaitFor потока, который в это время выполняет Synchronize с этой формой.
В идеале от Synchronize надо полностью избавляться. Например, постить форме сообщения, а она уже в контексте главного потока будет что-то делать.
Если без него ну совсем никак, то схема д.б. асинхронная:
- Вызвали закрытие формы:
-- проверить, не завершен ли поток, если да - то удалить его и закрыться
-- если не закрыт:
--- выставить флаг завершения (terminate)
--- Запостить себе повторный WM_CLOSE -либо- ждать от потока сообщения "я завершился"
-- на выход без закрытия
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839852
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Василий 2BasketbolВ итоге к чему я пришел:
1. Поток видит форму через свое поле. Поток должен знать о своей форме, ведь он с ней выполняет какие то действия.
2. Форма видит поток также через свое поле. Форма должна знать об управляющем потоке, ведь она должна его уничтожить во время своего закрытия.
3. Все действия с формой нужно реализовывать в классе потока. Во первых чтобы можно было использовать синхронайз, во вторых - чтобы постоянно анализировать terminate, дабы прекращать всяческие циклические операции когда форму закроет пользователь.
Есть вероятность дедлока, когда форма из OnClose вызовет WaitFor потока, который в это время выполняет Synchronize с этой формой.
В идеале от Synchronize надо полностью избавляться. Например, постить форме сообщения, а она уже в контексте главного потока будет что-то делать.
Если без него ну совсем никак, то схема д.б. асинхронная:
- Вызвали закрытие формы:
-- проверить, не завершен ли поток, если да - то удалить его и закрыться
-- если не закрыт:
--- выставить флаг завершения (terminate)
--- Запостить себе повторный WM_CLOSE -либо- ждать от потока сообщения "я завершился"
-- на выход без закрытия
Не возможно вызвать одновременно WaitFor в OnClose и функцию из Synchronize - так что дедлоков тут не должно быть, т. к. эти функции исполняются в основном потоке.
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839855
Василий 2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ziv-2014Не возможно вызвать одновременно WaitFor в OnClose и функцию из Synchronize - так что дедлоков тут не должно быть, т. к. эти функции исполняются в основном потоке.
А. Ну да.
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839883
Zelius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Василий 2ziv-2014Не возможно вызвать одновременно WaitFor в OnClose и функцию из Synchronize - так что дедлоков тут не должно быть, т. к. эти функции исполняются в основном потоке.
А. Ну да.
а если в Synchronize вызвать Application.PrcoessMessages?
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839888
Фотография makhaon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
замечу, что кроме Synchronize существует Queue:
http://docwiki.embarcadero.com/Libraries/XE5/en/System.Classes.TThread.Queue
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839900
Фотография defecator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Есть такая офигенная библиотека GS.Bus - *InterThread* communication Application Bus for FPC/Delphi
https://github.com/VincentGsell/GS.Core

Библиотека для пользователя простая и надёжная, пользуюсь давно и без проблем
Проблемы с синхронизациями куч потоков решаются целиком и полностью
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839929
ziv-2014
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ZeliusВасилий 2пропущено...

А. Ну да.
а если в Synchronize вызвать Application.PrcoessMessages?
Какая разница - всеравно в основном потоке исполнится.
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839945
Фотография softwarer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BasketbolНо не могу понять как правильно реализовать мою задачу.
Максимально упрощенная задача:
Нужно выполнять параллельно несколько потоков, которые меняют свойство progress компонента-бегунка TGaude.
Эту задачу правильно решить так. Каждый поток либо имеет собственные показатели прогресса (типа полей "сколько сделано" и "сколько всего надо") либо использует общие (например, когда одна задача делится на кучу исполняемых фрагментов). Доступ к показателям атомарный (например, через Interlocked-функции). На форме размещён таймер, который забирает эти данные, высчитывает и показывает прогресс.
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839946
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ziv-2014Не возможно вызвать одновременно WaitFor в OnClose и функцию из Synchronize - так что дедлоков тут не должно быть, т. к. эти функции исполняются в основном потоке.Ну почему же.
Можно, например, внутри Synchronize вызвать Form1.Close;
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839951
Zelius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ziv-2014Zeliusпропущено...

а если в Synchronize вызвать Application.PrcoessMessages?
Какая разница - всеравно в основном потоке исполнится.

доп поток вызывает Syncrhonize, в котором вызывается Application.PrcoessMessages, в это время пользователь нажимает закрыть форму, у которой в OnClose стоит FThread.Free (Terminate+WaitFor+Destroy), а поток висит в TMonitor.Wait(SyncProcPtr.Signal, ThreadLock, INFINITE) - дедлок. Если поток уничтожать в OnDestroy, то дедлока не будет.

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
    FThread: TThread;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  FThread.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FThread := TMyThread.Create;
end;

{ TMyThread }

procedure TMyThread.Execute;
begin
  Synchronize(
    procedure
    var
      i: Integer;
    begin
      i := GetTickCount;
      while (GetTickCount - i) < 3000 do
      begin
        Application.ProcessMessages
      end
    end
  );
end;

end.
...
Рейтинг: 0 / 0
И опять про потоки и про формы
    #39839971
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Zeliusдоп поток вызывает Syncrhonize, в котором вызывается Application.PrcoessMessages, в это время пользователь нажимает закрыть форму, у которой в OnClose стоит FThread.Free
Ну вот, еще как вариант.
ZeliusЕсли поток уничтожать в OnDestroy, то дедлока не будет.
Почему это. OnDestroy просто вызовется после OnClose, но это неважно, если это внутри Syncrhonize.
...
Рейтинг: 0 / 0
25 сообщений из 29, страница 1 из 2
Форумы / Delphi [игнор отключен] [закрыт для гостей] / И опять про потоки и про формы
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]