Delphi - 在单次成功执行或用户取消后终止线程

时间:2014-03-21 21:12:00

标签: multithreading delphi delphi-xe3

新来的。对Delphi来说相对较新,所以请亲切...

我的实际(域)问题:小型VCL应用程序通过串行与两个实验室天平通信,以连续的1秒间隔平衡输出重量读数,称重量显示在两个标签的标题中。当用户点击“称重”按钮时,我需要等待有效重量(稳定,在范围内等)并记录所述重量一次,或者 - 允许用户取消称重。

我的问题已经实施。使用S.MAHDI / David Heffernan的TEvent模板在用户点击称重按钮时创建单独的线程,如this post所示。

TWeigh = class(TThread)
  private
    FTerminateEvent: TEvent;
  protected
    procedure Execute; override;
    procedure TerminatedSet; override;
  public
    constructor Create(ACreateSuspended: Boolean);
    destructor Destroy; override;
end;

constructor TWeigh.Create(ACreateSuspended: Boolean);
begin
  FTerminateEvent := TEvent.Create(nil, True, False, '');
  inherited;
end;

destructor TWeigh.Destroy;
begin
  inherited;
  FTerminateEvent.Free;
end;

procedure TWeigh.TerminatedSet;
begin
  FTerminateEvent.SetEvent;
  Beep;
end;

procedure TWeigh.Execute();
begin
  while (not Terminated) do begin
    if (validweight) then begin
      Synchronize(procedure begin
        DoStuff();
      end);
    end;
    FTerminateEvent.WaitFor(100);
  end;
end;

我的表单按钮点击事件如下:

{ Weigh is global implementation var of class TWeigh }
procedure TForm1.btnWeighClick(Sender: TObject);
var
  B : TButton;
begin
  B := Sender as TButton;
  if (B.Caption = 'Weigh') then Weigh := TWeigh.Create(False);
  if (B.Caption = 'Cancel') then Weigh.Free;
  B.Caption := Trim(Copy('CancelWeigh ',AnsiPos(B.Caption,'Weigh Cancel'),6));
end;

这似乎适用于取消要求。我的理解是同步消息主线程并且它是执行包含DoStuff()的匿名过程的主线程,因此用户点击取消和有效权重之间应该没有竞争条件。(对吗?)

我坚持如何让称重线程只执行一次。我尝试过的各种解决方案导致了死锁(将Weigh.Free添加到DoStuff()......并没有花很长时间来弄清楚为什么这不起作用),单个执行但非自由线程(自我。在if块中的同步部分之后终止,或者其他各种废话。

那么,是否有可能让这个线程自由和/或自杀,同时仍允许通过用户输入的父线程杀死它,或者我是否需要一个完全不同的架构?

编辑以回应为什么循环:我只需要一个读数,但是直到我获得单个读数的时间在不同之间变化。天平可能需要几秒钟才能稳定,在此期间,每秒读取和显示不稳定的读数。仍然需要用户取消的能力,因为读数可能永远不会有效(超重)。

1 个答案:

答案 0 :(得分:3)

如果我理解正确,您希望在完成调用DoStuff后退出该主题。这可以这样做:

procedure TWeigh.Execute();
begin
  while (not Terminated) do begin
    if (validweight) then begin
      Synchronize(procedure begin
        DoStuff();
      end);
      exit;
    end;
    FTerminateEvent.WaitFor(100);
  end;
end;

我不得不说这看起来更适合于计时器而不是线程。所有的工作都在主线程上完成,线程似乎只是定期检查一个标志。这听起来像个计时器。事实上,为什么连一个计时器?为什么不在设置标志为真时触发DoStuff