Перейти к содержанию
Fire Monkey от А до Я
  • 0

Еще раз о потоках


DMS

Вопрос

Господа, подскажите, как вызвать друг за другом три процедуры с потоками внутри, но так - чтобы вызов каждой процедуры (начиная со второй) зависел от результатов предыдущей процедуры?

Поясняю примером:

procedure TForm1.Button1Click(Sender: TObject);
begin
  FirstThread;
  SecondThread;
  ThirdThread;
end;

procedure TForm1.FirstThread;
var
  I: Integer;
begin
  Memo1.Lines.Add('First Begin: ' + TimeToStr(Now));
  I := 0;

  TTask.Run(
    procedure
    begin
      while (I < 300000000) do
        Inc(I);

      TThread.Synchronize(TThread.CurrentThread,
        procedure
        begin
          Memo1.Lines.Add('First Thread: ' + TimeToStr(Now));
        end)
    end);

  Memo1.Lines.Add('First End: ' + TimeToStr(Now));
end;

procedure TForm1.SecondThread;
var
  I: Integer;
begin
  Memo1.Lines.Add('Second Begin: ' + TimeToStr(Now));
  I := 0;

  TTask.Run(
    procedure
    begin
      while (I < 800000000) do
        Inc(I);

      TThread.Synchronize(TThread.CurrentThread,
        procedure
        begin
          Memo1.Lines.Add('Second Thread: ' + TimeToStr(Now));
        end)
    end);

  Memo1.Lines.Add('Second End: ' + TimeToStr(Now));
end;

procedure TForm1.ThirdThread;
var
  I: Integer;
begin
  Memo1.Lines.Add('Third Begin: ' + TimeToStr(Now));
  I := 0;

  TTask.Run(
    procedure
    begin
      while (I < 900000000) do
        Inc(I);

      TThread.Synchronize(TThread.CurrentThread,
        procedure
        begin
          Memo1.Lines.Add('Third Thread: ' + TimeToStr(Now));
        end)
    end);

  Memo1.Lines.Add('Third End: ' + TimeToStr(Now));
end;

В Memo попадают сначала "Begin End" и только потом - First Thread, Second Thread, Third Thread.

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

Ссылка на комментарий

Рекомендуемые сообщения

  • 0
2 часа назад, DMS сказал:

В Memo попадают сначала "Begin End" и только потом - First Thread, Second Thread, Third Thread.

все правильно попадают. Вы же сами делаете TTask.Run, который создает доп. поток. То есть, последовательность выполнения каждого XXXThread получается следующая:
1. вывести Begin
2. запустить Task, который выполнится когда-нибудь.
3. вывести end.

когда все 3 пункта выполнились - стартуют внутренности TTask, которые выводят надпись Thread.

2 часа назад, DMS сказал:

чтобы вызов каждой процедуры (начиная со второй) зависел от результатов предыдущей процедуры?

Выполнение этого требования сводит на нет все преимущество, которое можно получить от потоков. Вы сознательно хотите последовательного выполнения операций. И несколько потоков становятся избыточными и даже вредными. Вполне хватит весь код запихнуть в один поток, что и позволит выполнить его (код) последовательно.

Ссылка на комментарий
  • 0

Я не спорю, что всё правильно Delphi делает. Я просто хочу спросить совета, как сделать так, чтобы и потоки были (против зависания), и можно было управлять их запуском. Спасибо!

Ссылка на комментарий
  • 0
1 час назад, DMS сказал:

ак сделать так, чтобы и потоки были (против зависания), и можно было управлять их запуском.

собственно, совет уже был дан: весь код запихать в 1 поток. Перед выполнением каждого следующего действия - проверять, а не прервали ли поток (if Terminated then exit). Не забывая высвобождать задействованные ресурсы.
Если же действия все-таки можно распараллелить (к примеру: есть огромный массив данных, над которым нужно выполнить x действий. Тогда делаем в одном потоке 1-е действие над y записями - отдаем второму потоку, а сами продолжаем обрабатывать дальше. Второй поток обработал часть данных - передал дальше. Минимизируется непроизводительный простой) - тогда есть смысл посмотреть в сторону пайпов в OmniThreadLibrary

Ссылка на комментарий
  • 0
  • Модераторы
22 часа назад, GASCHE сказал:

А что мешает дождаться завершения потока и по его результату запускать следующий?

Поток вызванный в синхронизации другого потока?)

Ссылка на комментарий
  • 0
24 минуты назад, Равиль Зарипов (ZuBy) сказал:

Поток вызванный в синхронизации другого потока?)

Так тоже интересно попробовать, но я имел ввиду WaitForAny или

 

Ссылка на комментарий
  • 0
12 часа назад, GASCHE сказал:

но я имел ввиду WaitForAny

В данном случае это всё избыточно и непроизводительно. Увеличивает сложность приложения без получения профита. Наоборот, производительность будет хуже. Особенно - на нагруженной системе.
С учетом условия

В 17.02.2018 в 13:20, DMS сказал:

вызвать друг за другом три процедуры

это всё надо делать в одном потоке.

Ссылка на комментарий
  • 0
2 часа назад, kami сказал:

С учетом условия это всё надо делать в одном потоке.

Да я согласен, но не ясно

В 17.02.2018 в 13:20, DMS сказал:

чтобы вызов каждой процедуры (начиная со второй) зависел от результатов предыдущей процедуры?

...

и можно было управлять их запуском

что автор имел ввиду под словами 'зависел и управлять', тут возможны разные толкования.

 

 

 

Изменено пользователем GASCHE
Ссылка на комментарий
  • 0
23 минуты назад, GASCHE сказал:

Да я согласен, но не ясно

что автор имел ввиду под словами 'зависел и управлять', тут возможны разные толкования.

 

 

 

Под "зависел" имелось в виду, запускать ли следующую процедуру или нет (в зависимости от результатов предыдущей процедуры)

Ссылка на комментарий
  • 0
14 минуты назад, DMS сказал:

Под "зависел" имелось в виду, запускать ли следующую процедуру или нет

Кто должен принимать решение программа или оператор?

Ссылка на комментарий
  • 0

Вставлю свои пять копеек, потому что также решал схожую с ТС задачу. Оказывается можно "штатными средствами" запускать потоки поочередно, точнее, дождаться в последующем потоке выполнения предыдущего.

Вот пример

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
  FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    CornerButton1: TCornerButton;
    ProgressBar1: TProgressBar;
    Memo1: TMemo;
    procedure Timer1Timer(Sender: TObject);
    procedure CornerButton1Click(Sender: TObject);
    procedure Procedure1(i: integer);
    procedure Procedure2(i: integer);
    procedure Procedure3;
    procedure ThreadProcedure(t: TThread);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.Procedure1(i: integer);
begin
  Form1.Memo1.lines.add('Thread2 - ' + inttostr(i));
end;

procedure TForm1.Procedure2(i: integer);
begin
  Form1.Memo1.lines.add('Thread3 - ' + inttostr(i));
end;

procedure TForm1.Procedure3;
begin
  Form1.Memo1.lines.add('Thread1 - OK');
end;

procedure TForm1.ThreadProcedure;
var
  i: integer;
begin
  for i := 0 to 5 do
  begin
    TThread.synchronize(t,
      procedure
      begin
        Form1.Procedure1(i);
      end);
    sleep(500);
  end;
end;

procedure TForm1.CornerButton1Click(Sender: TObject);
var
  thread1: TThread;
  thread2: TThread;
  thread3: TThread;
begin
  Timer1.Enabled := true;
  thread1 := TThread.CreateAnonymousThread(
    procedure
    begin
      thread2 := TThread.CreateAnonymousThread(
        procedure
        begin
         ThreadProcedure(thread2);
        end);
      thread2.freeonterminate := false;
      thread2.start;

      thread3 := TThread.CreateAnonymousThread(
        procedure
        var
          i: integer;
        begin
          thread2.WaitFor;  //ожидаем завершения потока 2
          thread2.Free;
          for i := 0 to 5 do
          begin
            TThread.synchronize(thread3,
              procedure
              begin
                Form1.Procedure2(i);
              end);
            sleep(500);
          end;

        end);
      thread3.freeonterminate := false;
      thread3.start;

      thread3.WaitFor;   //ожидаем завершения потока 3
      thread3.Free;
      TThread.synchronize(thread1,
        procedure
        begin
          Form1.Procedure3;
          Timer1.Enabled := false;
        end);
    end);

  thread1.freeonterminate := true;
  thread1.start;

end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  ProgressBar1.Value := ProgressBar1.Value + 1;
end;

end.

Проверил на Windows и Андроид, работает штатно 

Ссылка на комментарий

Присоединяйтесь к обсуждению

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

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...