Конференция "Начинающим" » Еще один вопрос по потокам [D2005]
 
  • fics © (09.04.17 18:39) [0]
    Как нужно правильно, не дожидаясь окончания выполнения Execute, прервать выполнение кода потока и освободится - NewThread.Free;?
    TNewThread = class(TThread)
     private
       { Private declarations }
     protected
       procedure Execute; override;
     end;

    var
     Form1: TForm1;

    implementation

    {$R *.dfm}

    { TNewThread }

    procedure TNewThread.Execute;
    begin
     while true do {ничего не делаем};
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    var
     NewThread: TNewThread;
    begin
     NewThread:=TNewThread.Create(true);
     NewThread.FreeOnTerminate:=true;
     NewThread.Priority:=tpLower;
     NewThread.Resume;
    end;

  • Юрий Зотов © (09.04.17 18:47) [1]

    procedure TNewThread.Execute;
    begin
     while not Terminated do {ничего не делаем};
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    var
     NewThread: TNewThread;
    begin
     NewThread := TNewThread.Create(true);
     NewThread.FreeOnTerminate := true;
     NewThread.Priority := tpLower;
     NewThread.Resume;
     Sleep(2000); // Дадим потоку NewThread поработать 2 секунды
     NewThread.Terminate; // а затем прервем его работу.
    end;
  • fics © (09.04.17 19:00) [2]

    > Sleep(2000); // Дадим потоку NewThread поработать 2 секунды

    А без этого?
  • Юрий Зотов © (09.04.17 19:01) [3]
    Пояснение.

    Вызов метода Terminate не прерывает работу потока NewThread немедленно, а только выставляет его флаг завершения (свойство Terminated).

    В методе Execute этот флаг проверяется и если он выставлен, то происходит выход из метода Execute, что приводит к реальному завершению потока.
  • Юрий Зотов © (09.04.17 19:06) [4]
    > fics ©   (09.04.17 19:00) [2]

    > А без этого?


    Нет проблем. Поток NewThread стартует (т.к. вызван метод Resume) и тут же завершится (т.к. Terminated = true).
  • fics © (09.04.17 19:16) [5]
    Ясно.

    Вот, к примеру, если при новом нажатии клавиши вызов от предыдущего нажатия еще не доработал, то екстренно прервать его и начать выполнение сначала вообще не получится?
    procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
    begin
     NewThread.Еxecute;
    end;


    Посему получается, что будет сделать это вообще нереально.
  • fics © (09.04.17 19:21) [6]

    > Нет проблем. Поток NewThread стартует (т.к. вызван метод
    > Resume) и тут же завершится (т.к. Terminated = true).

    ну так не устраивает, нужно при необходимости быстро оборвать поток и начать заново. Чтобы это было не заметно в FormKeyPress при вводе текста в редактор
  • Юрий Зотов © (09.04.17 19:24) [7]
    Начать новое выполнение того же самого потока без его завершения - не получится. А прямой вызов NewThread.Еxecute вообще не запускает новый поток, а только выполняет метод Execute в вызвавшемпотоке.
  • Игорь Шевченко © (09.04.17 19:38) [8]
    fics ©   (09.04.17 19:16) [5]

    Было бы гораздо легче и полезнее, если бы была озвучена реальная задача, которую надо решить.
  • fics © (09.04.17 19:41) [9]
    Что же делать:) Не в отдельном потоке тоже не получиься выходить из фунции так вызовы все равно в стеке
  • Юрий Зотов © (09.04.17 19:50) [10]
    > fics ©   (09.04.17 19:41) [9]

    > Что же делать:)


    То, что сказал Игорь - озвучить реальную задачу.

    Причем именно саму реальную задачу, а не предполагаемые Вами способы ее решения. Способы найдем вместе.
  • fics © (09.04.17 19:54) [11]

    > Игорь Шевченко ©   (09.04.17 19:38) [8]
    >
    > fics ©   (09.04.17 19:16) [5]
    >
    > Было бы гораздо легче и полезнее, если бы была озвучена
    > реальная задача, которую надо решить.

    Озвучиваю.
    Самописный редактор с подсветкой строк, комментариев итд , где при вводе нового символа нужно запускать весь текст на анализ. При новом нажатии клавиши предыдущее сканирование становиться бессмысленным. А сканирования большого файла может длится секунды.
  • Игорь Шевченко © (09.04.17 20:08) [12]
    fics ©   (09.04.17 19:54) [11]

    Найди исходники Far Colorer - он это делает мгновенно.
  • fics © (09.04.17 22:53) [13]

    > Найди исходники Far Colorer - он это делает мгновенно.

    Файл в несколько сот тысяч строк он мгновенно не обработает. И при быстром вводе пересканировка наверняка запускается  заново. Ну буду копать, делать нечего.
  • Юрий Зотов © (10.04.17 00:31) [14]
    Подсветка (рисование) происходит непосредственно по ходу парсинга?
  • rrrrr © (10.04.17 09:02) [15]
    ну так не устраивает, нужно при необходимости быстро оборвать поток и начать заново.

    не нужно.

    старый экземпляр - такой же точно (не хуже) чем тот который ты хочешь запустить.
    а тот который ты хочешь запустить - ничем не лучше того, который уже запущен.

    все что ты тут делаешь (вместо полезного) - насилуешь систему, зачем-то стартуя и останавливая свои потоки.
  • kilkennycat © (10.04.17 09:16) [16]

    > при вводе нового символа нужно запускать весь текст на анализ

    вот есть такой текст:
    тут тыща строк
    <wrap>ща мы тут введем новый символ</wrap>
    и тут тыща строк


    зачем запускать весь текст на анализ, ведь по сути, ничего не изменилось?

    другой вариант:

    <wrap>
    тут тыща строк
    <superwrap>ща мы тут испортим закрывающий тег</superwrap>
    и тут тыща строк
    <superwrap>
    и тут тыща строк
    </superwrap>
    </wrap>


    и даже в этом случае изменилась лишь координата </superwrap>, анализировать весь текст - бессмысленно и беспощадно
  • Leonid Troyanovsky © (10.04.17 09:50) [17]

    > fics ©   (09.04.17 19:54) [11]

    > где при вводе нового символа нужно запускать весь текст на анализ.

    Можно хоть в одном потоке всё организовать.
    Обработку запускать при срабатывании таймера простоя.

    Только саму обработку вести небольшими порциями,
    дабы быстро реагировать на возобновление ввода.

    See also
    https://rsdn.org/forum/delphi/942829.1

    --
    Regards, LVT.
  • sniknik © (10.04.17 10:10) [18]
    > И при быстром вводе пересканировка наверняка запускается  заново.
    т.е. ты не нашел, не попробовал, не знаешь наверняка, а просто предполагаешь?

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

    Far Colorer скорее всего организован также, а значит количество текста не влияет на скорость "покраски".
  • fics © (10.04.17 10:46) [19]

    > Подсветка (рисование) происходит непосредственно по ходу
    > парсинга?

    нет - строится массив состояний.
  • fics © (10.04.17 10:51) [20]

    > kilkennycat ©   (10.04.17 09:16) [16]

    Так у меня полной пересканировки и нет при вводе обычных символов. Она запускается только при вводе кавычек и комментария и то с места их ввода и до конца
  • fics © (10.04.17 11:03) [21]

    > Leonid Troyanovsky ©   (10.04.17 09:50) [17]


    > sniknik ©   (10.04.17 10:10) [18]

    Буду колдовать с таймером.
    Было что-то типа:
    Scan;
    begin
     n := 1;
     while n <> Length(Text) do begin
       {-----}
       inc(n)
     end;
    end;


    А теперь что-то из этого мудрить нужно
  • NoUser © (10.04.17 11:48) [22]
    while n <> Length(Text) do begin
      if ( fNewText ) then Break;
      {-----}  
      inc(n)
    end;

  • fics © (10.04.17 15:35) [23]

    > NoUser ©   (10.04.17 11:48) [22]
    >
    > while n <> Length(Text) do begin
    >   if ( fNewText ) then Break;
    >   {-----}  
    >   inc(n)
    > end;

    Ну без задержки таймером все равно не получиться, так как и fNewText
    и вызов Scan идут с одной точки, оборвать так конечно можно, но нужно как-то ждать выхода из функции. Без таймера тут не обойтись, так как:

    unit Unit1;

    interface

    uses
     Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
     Dialogs, StdCtrls;

    type
     TForm1 = class(TForm)
       Label1: TLabel;
       Label2: TLabel;
       procedure FormKeyPress(Sender: TObject; var Key: Char);
       procedure FormActivate(Sender: TObject);
     private
       { Private declarations }
     public
       SyspendFlag: Boolean;
       function Scan: Boolean;
     end;

    var
     Form1: TForm1;

    implementation

    {$R *.dfm}

    procedure TForm1.FormActivate(Sender: TObject);
    begin
     SyspendFlag := False;
     Scan;
    end;

    function TForm1.Scan: Boolean;
    var
     n: Integer;
    begin
     n := 0;
     while  n < 214748364 do begin
       if SyspendFlag then begin
         Label2.Caption := IntToStr(n);   {тут всегда будет ноль}
         Break;
       end;
       Inc(n);
       Application.ProcessMessages;
     end;

     SyspendFlag := False;
    end;

    procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
    begin
     SyspendFlag := True;
     Label1.Caption := Key;
     Scan;
    end;
  • NoUser © (10.04.17 17:01) [24]
    type
     TForm1 = class(TForm)
       Memo1: TMemo;
       Label1: TLabel;
       procedure Memo1KeyPress(Sender: TObject; var Key: Char);
       procedure FormClose(Sender: TObject; var Action: TCloseAction);
     private
       fInScan :Boolean;
       fReScan :Boolean;
       fBrScan :Boolean;
       function Scan: Boolean;
       procedure WmUser100(var Msg:TMessage); message WM_USER+1;
     end;
    var
     Form1: TForm1;

    implementation

    {$R *.dfm}

    function TForm1.Scan: Boolean;
    var
     n: Integer;
    begin
     fInScan := True;
     fBrScan := False;
     n := 0;
     while  n < 214748364 do begin
       if (fReScan) then begin
         fReScan := False;
         Memo1.Lines.Add(IntToStr(n));
         n := 0;
       end;
       if (fBrScan)
         then Break;
       Inc(n);
       Application.ProcessMessages;
     end;
     fInScan := False;
    end;

    procedure TForm1.WmUser100(var Msg: TMessage);
    begin
    if ( fInScan )
      then fReScan := True
      else Scan;
    end;

    procedure TForm1.Memo1KeyPress(Sender: TObject; var Key: Char);
    begin
    PostMessage(Handle, WM_USER+1,0,0);
    end;

    procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
    fBrScan := True;
    end;
  • fics © (10.04.17 19:22) [25]

    > NoUser ©   (10.04.17 17:01) [24]

    Ну концептуально примерно правильно, но где fBrScan становится истинным, кроме как при закрытии формы?
    Ведь нужно же обрывать цикл при новом вводе, а выход только по
    if (fBrScan) then Break;



    И это не правильная логика, если Scan будет успевать дорабатывать до конца, то нового Скана не будет

    procedure TForm1.WmUser100(var Msg: TMessage);
    begin
    if ( fInScan )
      then fReScan := True
      else Scan;
    end;
  • fics © (10.04.17 20:26) [26]
    точнее при первом нажатии клавиши мы оборвем предыдущий цикл, а новый не начнем.

    правильнее наверное будет так:   (но только наверное ) нужно потестировать

    function TForm1.Scan: Boolean;
    var
     n: Integer;
    begin
     fInScan := True;
     n := 0;
     while  n < 214748364 do begin
       if (fReScan) then begin
         fReScan := False;
         Scan; {вызов после прекращения предыдущего}
         Break;
       end;
       Inc(n);
       Application.ProcessMessages;
     end;

     fInScan := False;
    end;
  • NoUser © (11.04.17 02:03) [27]

    > Ведь нужно же обрывать цикл при новом вводе,

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

    А обрывать, это если юзеру уже нужно новый документ или винда пошла обновляться. ))


    > если Scan будет успевать дорабатывать до конца, то нового Скана не будет

    отлично, значит успели просканить до ввода нового символа - как и задумано!
 
Конференция "Начинающим" » Еще один вопрос по потокам [D2005]
Есть новые Нет новых   [118621   +7][b:0][p:0.002]