delphi - 等待全局变量改变其值

标签 delphi

我创建了以下抽象代码,其中用户有 2 个按钮:

  • 一个按钮即可启动某种进程。全局变量 PleaseStop 将告诉正在运行的进程应该停止工作。

  • 另一个按钮设置全局变量PleaseStop,它将告诉程序停止。

-

var
  PleaseStop: boolean;
  IsRunning: boolean;

procedure TForm1.RunActionClick(Sender: TObject);
var
  rnd: integer;
  tic: Cardinal;
begin
  try
    IsRunning := true;
    rnd := Random(100);
    while not PleaseStop do
    begin
      tic := GetTickCount;
      while (GetTickCount-tic < 1000) and not PleaseStop do
      begin
        Application.ProcessMessages;
        Sleep(10);
      end;
      Memo1.Lines.Add(IntToStr(rnd));
    end;
  finally
    IsRunning := false;
    PleaseStop := false;
  end;
end;

procedure TForm1.StopBtnClick(Sender: TObject);
begin
  PleaseStop := true;
end;

一切都按预期进行。

现在,如果用户不单击“停止”按钮,而是再次单击“运行”按钮(应该允许),就会出现问题。

我现在修改了我的代码,如下所示:

var
  PleaseStop: boolean;
  IsRunning: boolean;

procedure TForm1.Button1Click(Sender: TObject);
var
  rnd: integer;
  tic: Cardinal;
begin
  // ---- BEGIN NEW ----
  if IsRunning then
  begin
    PleaseStop := true; // End the previous actions
    while PleaseStop do // Wait until the previous actions are done
    begin
      // TODO: this loop goes forever. PleaseStop will never become false
      Application.ProcessMessages;
      Sleep(10);
    end;
    // Now we can continue
  end;
  // ---- END NEW ----

  try
    IsRunning := true;
    rnd := Random(100);
    while not PleaseStop do
    begin
      tic := GetTickCount;
      while (GetTickCount-tic < 1000) and not PleaseStop do
      begin
        Application.ProcessMessages;
        Sleep(10);
      end;
      Memo1.Lines.Add(IntToStr(rnd));
    end;
  finally
    IsRunning := false;
    PleaseStop := false;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  PleaseStop := true;
end;

再次单击“开始”按钮将导致死锁。 我假设编译器认为 while PleaseStop do 等于 while true do 因为我刚刚将 PleaseStop 设置为 true早些时候。但事实上,这个变量应该被监控...

我还尝试将 [volatile] 放在变量前面,并使它们成为 TForm1 的成员,但这也不起作用。

为什么我没有使用线程?

  • 该代码严重依赖于 VCL。

  • 运行按钮将启动 dia show。每次单击运行按钮时,都会选择一个随机图片文件夹。

  • 所以,当用户不喜欢这些图片时,他会再次单击“运行”以切换到新文件夹并自动启动新的dia show。因此,之前的运行应该停止。

最佳答案

您的诊断并不完全准确,ProcessMessages 根本无法导致先前检索到的消息的处理继续进行。您必须停止处理并让执行从发生重入的地方继续。重入是避免 Application.ProcessMessages 的主要原因,而您是故意这样做的。很难解决...

如果你不想使用同步和线程,你可以使用定时器来代替。代码也会简单得多。

procedure TForm1.FormCreate(Sender: TObject);
begin
  Timer1.Enabled := False;
  Randomize;
end;

var
  rnd: Integer;

procedure TForm1.StartClick(Sender: TObject);
begin
  rnd := Random(100);
  Timer1.Enabled := True;
end;

procedure TForm1.StopClick(Sender: TObject);
begin
  Timer1.Enabled := False;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
   Memo1.Lines.Add(IntToStr(rnd));
end;

关于delphi - 等待全局变量改变其值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45536203/

相关文章:

.net - .NET 和 Delphi 中的多个键盘 Hook

xml - Delphi Xpath XML 查询

c# - C# 与 Delphi 中日期/时间计算之间的差异

wpf - Delphi 中的 Dxscene 和 VGscene

arrays - 使用后数组的长度是否应该设置为零?

delphi - 如何在VCL项目中包含FMX.Types

Delphi - 智能指针和泛型 TList

android - Delphi Android密码保护一个文件

delphi - 用于 DelphiXE 的 THtmlViewer

delphi - 以编程方式更改快捷方式图标