Вопрос по потокам (TThread и lazarus)

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Вопрос по потокам (TThread и lazarus)

Сообщение Михаил Крамер » 19.03.2009 14:59:58

Возникла необходимость пременить потоки в Linux. Причём не программировал потоки очень давно. Чтобы вспомнить, состряпал примерчик (Привожу только модуль формы):
Код: Выделить всё
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ExtCtrls,
  StdCtrls;

type
    { TPaintThread1 }
    TPaintThread1 = class (TThread)
    public
        procedure Execute; override;
    end;

  { TForm1 }
  TForm1 = class(TForm)
    Button1: TButton;
    PaintBox1: TPaintBox;
    PaintBox2: TPaintBox;
    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
  private
    { private declarations }
    a : TThread;
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{ TPaintThread1 }

procedure TPaintThread1.Execute;
var
    x, y, r: Integer;
begin
    while true do with form1.PaintBox1.Canvas do
    begin
        x:= Random(3 * form1.PaintBox1.Width div 4);
        y:= Random(3 * Form1.PaintBox1.Height div 4);
        r:= random(3 * form1.PaintBox1.Width div 4);
        Brush.Color:= Random($FFFF);
        Pen.Color:= Random($FFFF);
        EllipseC(x, y, r, r);
    end;
end;

{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
begin
  a:= TPaintThread1.Create(false);
end;

procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  a.Terminate;
end;

initialization
  {$I unit1.lrs}

end.


Судя по работе никакой многопотоковости нет и в помине, поскольку кнопки формы перестают работать после запуска потока, и завершается программа только командой kill. В чём может быть дело?
Михаил Крамер
новенький
 
Сообщения: 73
Зарегистрирован: 08.02.2008 14:26:40

Re: Вопрос по потокам (TThread и lazarus)

Сообщение yser » 19.03.2009 15:30:39

подозреваю что поток забирает 100% проц. времени.
попробуй в потоке sleep(1) например.
yser
новенький
 
Сообщения: 29
Зарегистрирован: 06.02.2008 11:27:40

Re: Вопрос по потокам (TThread и lazarus)

Сообщение Mr.Smart » 19.03.2009 16:37:24

Михаил Крамер писал(а):Возникла необходимость пременить потоки в Linux. Причём не программировал потоки очень давно. Чтобы вспомнить, состряпал примерчик (Привожу только модуль формы):
Код: Выделить всё
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ExtCtrls,
  StdCtrls;

type
    { TPaintThread1 }
    TPaintThread1 = class (TThread)
    public
        procedure Execute; override;
    end;

  { TForm1 }
  TForm1 = class(TForm)
    Button1: TButton;
    PaintBox1: TPaintBox;
    PaintBox2: TPaintBox;
    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
  private
    { private declarations }
    a : TThread;
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{ TPaintThread1 }

procedure TPaintThread1.Execute;
var
    x, y, r: Integer;
begin
    while true do with form1.PaintBox1.Canvas do
    begin
        x:= Random(3 * form1.PaintBox1.Width div 4);
        y:= Random(3 * Form1.PaintBox1.Height div 4);
        r:= random(3 * form1.PaintBox1.Width div 4);
        Brush.Color:= Random($FFFF);
        Pen.Color:= Random($FFFF);
        EllipseC(x, y, r, r);
    end;
end;

{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
begin
  a:= TPaintThread1.Create(false);
end;

procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  a.Terminate;
end;

initialization
  {$I unit1.lrs}

end.


Судя по работе никакой многопотоковости нет и в помине, поскольку кнопки формы перестают работать после запуска потока, и завершается программа только командой kill. В чём может быть дело?

А где синхронизация? Где вызовы Synchronize? Возникают "гонки"........
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Вопрос по потокам (TThread и lazarus)

Сообщение Bupyc » 19.03.2009 16:45:50

yser прав. В цикле надо добавить Sleep(). Хотя его отсутствие не должно приводить к зависанию приложения (по-крайней мере так будет в Windows). Но есть еще один момент. Приведённый код обращается к объектам GUI из потока. Иногда это конечно прокатывает :) , но вообще так не делается. Для того, что бы обратиться к GUI из потока нужно использовать метод TThread.Synchronize();
Т.е. код должен выглядеть примерно так (за 100% правильность синтаксиса не ручаюсь):

Код: Выделить всё

procedure TPaintThread1.GUICall();
var
    x, y, r: Integer;
begin
  with form1.PaintBox1.Canvas do
begin
        x:= Random(3 * form1.PaintBox1.Width div 4);
        y:= Random(3 * Form1.PaintBox1.Height div 4);
        r:= random(3 * form1.PaintBox1.Width div 4);
        Brush.Color:= Random($FFFF);
        Pen.Color:= Random($FFFF);
        EllipseC(x, y, r, r);
end;
end;

procedure TPaintThread1.Execute;
begin
    while not Terminated do
    begin
     Synchronize(@GUICall);
     Sleep(1);
    end;
end;

Bupyc
постоялец
 
Сообщения: 137
Зарегистрирован: 29.08.2007 18:22:42

Re: Вопрос по потокам (TThread и lazarus)

Сообщение Михаил Крамер » 19.03.2009 17:05:26

Благодарю. Обязательно проверю

Добавлено спустя 22 часа 42 минуты 44 секунды:
Изменил код в соответствии с рекомендациям, даже добавил второй поток, рисующий квадратики в PaintBox2. Многопотоковость заработала - квадратики и кружочки рисуются "одновременно".

Но возникла странность с завершением потоков. При попытке завершить потоки вызовами Terminate в обработчике OnClose программа то виснет, то выдаёт различные RunTime Errors (номер 6, системные сигналы и т.п.) Но стоит добавить вторую кнопку и в перенести вызовы Terminate в её OnClick - всё в порядке, и потоки завершаются, и программа после этого закрывается. Я не понимаю разницу...
Михаил Крамер
новенький
 
Сообщения: 73
Зарегистрирован: 08.02.2008 14:26:40

Re: Вопрос по потокам (TThread и lazarus)

Сообщение anzo » 10.07.2009 11:42:48

Для правильного завершения работы потока, нужно устанавливать у него свойство FreeOnTerminate = true или при завершении работы программы
после вызова Terminate в главном потоке вызвать у дочернего потока метод WaitFor, а после уже Free
anzo
новенький
 
Сообщения: 28
Зарегистрирован: 09.07.2009 10:53:46

Re: Вопрос по потокам (TThread и lazarus)

Сообщение EmeraldMan » 10.07.2009 12:01:40

Признаться в Линуксе с потоками не работал, а вы не пробовали приоритет поменьше установить?
Код: Выделить всё
Thread.Priority := tpLower;

Так просто "правильнее" будет, чем Sleep использовать.
Аватара пользователя
EmeraldMan
постоялец
 
Сообщения: 149
Зарегистрирован: 16.10.2008 08:41:51
Откуда: Белгород

Re: Вопрос по потокам (TThread и lazarus)

Сообщение Mr.Smart » 10.07.2009 14:17:59

Михаил Крамер писал(а):Но возникла странность с завершением потоков. При попытке завершить потоки вызовами Terminate в обработчике OnClose программа то виснет, то выдаёт различные RunTime Errors (номер 6, системные сигналы и т.п.) Но стоит добавить вторую кнопку и в перенести вызовы Terminate в её OnClick - всё в порядке, и потоки завершаются, и программа после этого закрывается. Я не понимаю разницу...

Тут дело скорее в том, что форма уничтожилась раньше чем дочерние потоки. И соответственно form1 уже несуществует, а поток пытается к ней обратится!
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 39

Рейтинг@Mail.ru