我创建了以下抽象代码,其中用户有 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/