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事件而不是