Запрет повторного создания потока

  • Автор темы MODERN
  • Дата начала
MODERN
Участник
Сообщения
756
Реакции
130
Здравствуйте, товарищи. Сейчас я попытаюсь Вам объяснить как можно предотвратить двойной запуск потока.

Допустим, у вас в программе по нажатию кнопки создается поток - не важно, какую задачу он выполняет; просто, Вам нужно создать отдельный поток для какой-то фоновой работы, причем одновременно должна выполняться только 1 доп.поток. Как это сделать? Неопытные товарищи проверяют переменную, которой присвоили поток: не является ли ее значение Nil, либо с помощью Assigned (что, в принципе, одно и то же). Nil она будет только до того, как вы присвоили ей инстанс потока, потом все время будет Assigned, и этот путь не есть решение. Я выкрутился из положения так (см. код):

Код:
unit Unit1;

interface

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


  type
    tmythread=class(tthread)
    private
    protected
    procedure execute;override;
    public
    procedure OnTerminated(sender:tobject);
    constructor create;
    destructor destroy;override;
    end;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  thread:tmythread;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  if assigned(thread) then // если переменная thread не nil, то...
  begin
    if thread.Terminated then // если предыдущий инстанс завершил работу то...
    begin
      caption:='Creating new thread...';
      thread:=tmythread.Create; // создаем новый инстанс tmythread.
    end
    else
    begin
      // если предыдущий инстанс все еще выполняется(т.е. переменная thread еще занята), оповещаем юзера и выходим.
      showmessage('Thread already works!');
      abort;
    end;
  end
  else // если первый запуск...
  begin
    caption:='Creating new thread...';
    thread:=tmythread.Create;
  end;
end;

{ tmythread }

constructor tmythread.create;
begin
  inherited create(true);
  {Создаем "спящий поток". Выполнение не будет продолжено до вызова Resume}
  onterminate:=onterminated;
  freeonterminate:=true;
  resume; // Продолжаем поток - теперь будет выполнен код, находящийся в процедуре "Execute."
end;

destructor tmythread.destroy;
begin
  terminate; // Terminate просто переставляет флаг Terminated в true, можете вызывать смело.
  inherited destroy;
end;

procedure tmythread.execute;
begin
  { все, что здесь написано, будет выполнено в отдельном потоке.
   Можно также написать указатель на процедуру/функцию, но лучше делать их методами класса}
  Sleep(2000);
  { нагружаем поток. Если бы процедура Sleep была вызвана в одном потоке с формой,
   форма зависла бы намертво.}
end;

procedure tmythread.OnTerminated(sender: tobject);
begin
  {Процедура, указанная как OnTerminate, выполняется в основном потоке, поэтому можете смело обращаться к VCl-контролам.}
  form1.Caption:='Thread terminated';
end;

end.
Теперь, сколько раз бы юзер не нажал кнопку, у вас будет только 1 доп.поток.
 
Сверху