Delphi:如何防止单线程应用程序丢失响应? [英] Delphi: How to prevent a single thread app from losing responses?

查看:435
本文介绍了Delphi:如何防止单线程应用程序丢失响应?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Delphi开发一个单线程应用程序,这将是一个耗时的任务,如下所示:

  / time-consumption循环
对于I:= 0到1024 * 65536 do
开始
DoTask();
结束;

当循环启动时,应用程序将失去对最终用户的响应。那不是很好我也不想把它转换为一个多线程的应用程序,因为它的复杂性,所以我相应地添加Application.ProcessMessages

  //耗时的循环
对于I:= 0到1024 * 65536 do
开始
DoTask();
Application.ProcessMessages;
结束;

但是,这一次虽然应用程序将响应用户操作,但循环中消耗的时间是比原来的循环要好多了10次。



有没有一个解决方案,以确保应用程序不会失去响应,而不要增加消耗的时间太多?

解决方案

你真的应该使用一个工作线程。这是线程是有益的。



使用 Application.ProcessMessages()是一个帮助,而不是解。您的应用程式仍然没有反应,而 DoTask()正在开展工作,除非您随附额外的电话( DoTask() Application.ProcessMessages()。另外,如果你不小心,调用 Application.ProcessMessages()直接引入可重入的问题。



如果你必须调用 Application.ProcessMessages()直接,除非有消息实际上等待处理,否则不要调用它。您可以使用Win32 API GetQueueStatus()函数检测该条件,例如:

 code> //耗时的循环
对于I:= 0到1024 * 65536 do
开始
DoTask();
如果GetQueueStatus(QS_ALLINPUT)<> 0 then
Application.ProcessMessages;
结束;

否则,移动 DoTask()进入一个线程(是的),然后让你的主要
循环使用 MsgWaitForMultipleObjects()等待任务线程完成。
这仍然允许您检测何时处理消息,例如:

 过程TMyTaskThread.Execute; 
begin
//耗时循环
为I:= 0到1024 * 65536 do
begin
如果终止然后退出;
DoTask();
结束
结束

  var 
MyThread:TMyTaskThread;
Ret:DWORD;
begin
...
MyThread:= TMyTaskThread.Create;
重复
Ret:= MsgWaitForMultipleObjects(1,Thread.Handle,FALSE,INFINITE,QS_ALLINPUT);
if(Ret = WAIT_OBJECT_0)或(Ret = WAIT_FAILED)then Break;
if Ret =(WAIT_OBJECT_0 + 1)then Application.ProcessMessages;
until False;
MyThread.Terminate;
MyThread.WaitFor;
MyThread.Free;
...
end;


I am developing a single thread app with Delphi, which will do a time-consuming task, like this:

// time-consuming loop
For I := 0 to 1024 * 65536 do
Begin
    DoTask();
End;

When the loop starts, the application will lose responses to the end user. That is not very good. I also do not want to convert it into a multi-thread application because of its complexity, so I add Application.ProcessMessages accordingly,

// time-consuming loop
For I := 0 to 1024 * 65536 do
Begin
DoTask();
Application.ProcessMessages;
End;

However, this time although the application will response to user operations, the time-consumed in the loop is much more than the original loop, about 10 times.

Is there a solution to make sure the application does not lose the response while do not increase the consumed time too much?

解决方案

You really should use a worker thread. This is what threads are good for.

Using Application.ProcessMessages() is a band-aid, not a solution. Your app will still be unresponsive while DoTask() is doing its work, unless you litter DoTask() with additional calls to Application.ProcessMessages(). Plus, calling Application.ProcessMessages() directly introduces reentrant issues if you are not careful.

If you must call Application.ProcessMessages() directly, then don't call it unless there are messages actually waiting to be processed. You can use the Win32 API GetQueueStatus() function to detect that condition, for example:

// time-consuming loop
For I := 0 to 1024 * 65536 do
Begin
  DoTask();
  if GetQueueStatus(QS_ALLINPUT) <> 0 then
    Application.ProcessMessages;
End;

Otherwise, move the DoTask() loop into a thread (yeah yeah) and then have your main loop use MsgWaitForMultipleObjects() to wait for the task thread to finish. That still allows you to detect when to process messages, eg:

procedure TMyTaskThread.Execute;
begin
  // time-consuming loop
  for I := 0 to 1024 * 65536 do
  begin
    if Terminated then Exit;
    DoTask();
  end;
end;

var
  MyThread: TMyTaskThread;
  Ret: DWORD;
begin
  ...
  MyThread := TMyTaskThread.Create;
  repeat
    Ret := MsgWaitForMultipleObjects(1, Thread.Handle, FALSE, INFINITE, QS_ALLINPUT);
    if (Ret = WAIT_OBJECT_0) or (Ret = WAIT_FAILED) then Break;
    if Ret = (WAIT_OBJECT_0+1) then Application.ProcessMessages;
  until False;
  MyThread.Terminate;
  MyThread.WaitFor;
  MyThread.Free;
  ...
end;

这篇关于Delphi:如何防止单线程应用程序丢失响应?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆