Delphi 等待全局变量更改其值

Delphi 等待全局变量更改其值,delphi,Delphi,我创建了以下抽象代码,其中用户有两个按钮: 一个按钮正在启动某种过程。全局变量PleaseStop将告诉正在运行的进程它应该停止工作 另一个按钮设置全局变量plessestop,该变量将通知程序停止 - var PleaseStop:布尔型; IsRunning:boolean; 过程TForm1.RunActionClick(发送方:TObject); 变量 rnd:整数; 议会:枢机主教; 开始 尝试 正在运行:=真; rnd:=随机(100); 虽然不高兴,但请不要这样做 开始 tic

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

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

  • 另一个按钮设置全局变量
    plessestop
    ,该变量将通知程序停止

-

var
PleaseStop:布尔型;
IsRunning:boolean;
过程TForm1.RunActionClick(发送方:TObject);
变量
rnd:整数;
议会:枢机主教;
开始
尝试
正在运行:=真;
rnd:=随机(100);
虽然不高兴,但请不要这样做
开始
tic:=GetTickCount;
而(GetTickCount tic<1000)则不希望这样做
开始
Application.ProcessMessages;
睡眠(10);
终止
备忘录1.行添加(IntToStr(rnd));
终止
最后
正在运行:=错误;
请点击:=假;
终止
终止
程序TForm1.StopBtnClick(发送方:TObject);
开始
请点击:=正确;
终止
一切正常

现在,如果用户没有单击停止按钮,而是再次单击运行按钮(这应该是允许的),就会出现问题

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

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;
var Needtorestart:Boolean = false;

procedure TForm1.Button1Click(Sender: TObject);
var
   rnd: integer;
   tic: Cardinal;
begin
  // ---- BEGIN NEW ----
  if IsRunning then
  begin
    PleaseStop := true; // End the previous action
    Needtorestart := true;
    Exit;
    // Now we can continue
  end;
      // ---- END NEW ----

  try
    repeat
        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;
         PleaseStop := false;
    until not Needtorestart;
  finally
    IsRunning := false;
    PleaseStop := false;
    Needtorestart := false;
  end;
end;
var
PleaseStop:布尔型;
IsRunning:boolean;
程序TForm1.按钮1单击(发送方:TObject);
变量
rnd:整数;
议会:枢机主教;
开始
//----开始新的生活----
如果正在运行,那么
开始
请点击:=true;//结束之前的操作
而请停止//等待,直到前面的操作完成
开始
//TODO:这个循环将永远持续下去。“快乐”永远不会变成虚假
Application.ProcessMessages;
睡眠(10);
终止
//现在我们可以继续了
终止
//----结束新的一天----
尝试
正在运行:=真;
rnd:=随机(100);
虽然不高兴,但请不要这样做
开始
tic:=GetTickCount;
而(GetTickCount tic<1000)则不希望这样做
开始
Application.ProcessMessages;
睡眠(10);
终止
备忘录1.行添加(IntToStr(rnd));
终止
最后
正在运行:=错误;
请点击:=假;
终止
终止
程序TForm1.按钮2单击(发送方:TObject);
开始
请点击:=正确;
终止
再次单击“开始”按钮将导致死锁。 我假设编译器认为
while plesestop do
等于
while true do
,因为我刚才将
plesestop
设置为
true
。但事实上,这个变量应该被监控

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

我为什么不使用线程?

  • 该代码严重依赖于VCL

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

  • 因此,当用户不喜欢图片时,他将再次单击“运行”切换到新文件夹并自动启动新的dia显示。因此,应停止上一次运行


您的诊断不准确,
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;

尝试按如下方式重写事件处理程序:

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;
var Needtorestart:Boolean = false;

procedure TForm1.Button1Click(Sender: TObject);
var
   rnd: integer;
   tic: Cardinal;
begin
  // ---- BEGIN NEW ----
  if IsRunning then
  begin
    PleaseStop := true; // End the previous action
    Needtorestart := true;
    Exit;
    // Now we can continue
  end;
      // ---- END NEW ----

  try
    repeat
        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;
         PleaseStop := false;
    until not Needtorestart;
  finally
    IsRunning := false;
    PleaseStop := false;
    Needtorestart := false;
  end;
end;
var需要启动:Boolean=false;
程序TForm1.按钮1单击(发送方:TObject);
变量
rnd:整数;
议会:枢机主教;
开始
//----开始新的生活----
如果正在运行,那么
开始
请点击:=true;//结束上一个操作
需要启动:=真;
出口
//现在我们可以继续了
终止
//----结束新的一天----
尝试
重复
正在运行:=真;
rnd:=随机(100);
虽然不高兴,但请不要这样做
开始
Tic:=GetTickCount;
而(GetTickCount tic<1000)则不希望这样做
开始
Application.ProcessMessages;
睡眠(10);
终止
备忘录1.行添加(IntToStr(rnd));
终止
请点击:=假;
直到不需要开始;
最后
正在运行:=错误;
请点击:=假;
需要启动:=false;
终止
终止

您可以在流程启动后禁用启动按钮<代码>按钮1.enabled:=false或者你可以编写带有关键部分的面向线程的代码等等。“现在如果用户不点击停止按钮,而是再次点击运行按钮(这应该是允许的)。”仅仅说“应该允许的事情”是不够的。关键的遗漏问题是:应该发生什么?当用户再次单击“运行”按钮时。1) 在第一次运行完成后立即开始第二次运行?2) 是否与第一次运行同时执行第二次运行?3) 忽略第二次点击?4) 完全是别的吗。。。。此外,如果1或2:是否应对“活动运行”的总数进行限制?在打印随机数的简化示例中,这是可行的。但在我的实际代码中,我确实需要通过出于各种原因发送“停止信号”来清理正在运行的Timer1Timer()操作。因此,我又遇到了同样的问题:我试图停止并等待StartClick()中的Timer1Time()代码,这将导致死锁。如果计时器正在运行,您可以进行清理/设置。我无法想象你的僵局情况,试着举出一个例子。问题基本上是一样的(我想?):。恐怕我不理解ProcessMessagesGet的问题,因为它删除了您以前的代码;循环和processmessages调用以及所有。计时器在指定的时间间隔内触发,请使用ontimer事件而不是