multithreading - 在长时间任务期间保持应用程序响应

标签 multithreading delphi callback

我们应用程序中的某个表单显示模型的图形 View 。用户可以在许多其他事情中发起模型转换,这可能需要相当长的时间。这种转换有时无需任何用户交互即可进行,有时则需要频繁的用户输入。当它持续时,除非需要用户输入,否则 UI 应被禁用(仅显示进度对话框)。

可能的方法:

  1. 忽略该问题,只需将转换代码放入过程中并调用即可。不好,因为在转换需要一些时间但不需要用户输入的情况下,应用程序似乎挂起。
  2. 在代码中添加回调:这很烦人 - 您必须在转换代码中放置很多这些调用 - 而且不可预测 - 您永远无法确定自己会这样做找到了正确的地点。
  3. 在代码中添加 Application.ProcessMessages:与回调相同的问题。此外,您还会遇到 ProcessMessages 的所有问题。
  4. 使用线程:这使我们摆脱了 2. 和 3 中“烦人且不可预测”的部分。然而,由于用户输入需要“编码”,所以工作量很大 - 调用 Synchronize,将任意内容放入定制记录中需要的参数等。调试起来也是一场噩梦,而且容易出错。

//编辑:我们当前的解决方案是线程。然而,由于用户输入,这是一个令人痛苦的事情。而且很多例程中可能有很多输入代码。这让我感觉线程不是正确的解决方案。

我要让自己难堪,并发布我所生成的 GUI 和工作代码的邪恶组合的概述:

type
  // Helper type to get the parameters into the Synchronize'd routine:
  PGetSomeUserInputInfo = ^TGetSomeUserInputInfo;
  TGetSomeUserInputInfo = record
    FMyModelForm: TMyModelForm;
    FModel: TMyModel;
    // lots of in- and output parameters
    FResult: Boolean;
  end;

{ TMyThread }

function TMyThread.GetSomeUserInput(AMyModelForm: TMyModelForm;
  AModel: TMyModel; (* the same parameters as in TGetSomeUserInputInfo *)): Boolean;
var
  GSUII: TGetSomeUserInputInfo;
begin
  GSUII.FMyModelForm := AMyModelForm;
  GSUII.FModel := AModel;
  // Set the input parameters in GSUII

  FpCallbackParams := @GSUII; // FpCallbackParams is a Pointer field in TMyThread
  Synchronize(DelegateGetSomeUserInput);
  // Read the output parameters from GSUII
  Result := GSUII.FResult;
end;

procedure TMyThread.DelegateGetSomeUserInput;
begin
  with PGetSomeUserInputInfo(FpCallbackParams)^ do
    FResult := FMyModelForm.DoGetSomeUserInput(FModel, (* the params go here *));
end;

{ TMyModelForm }

function TMyModelForm.DoGetSomeUserInput(Sender: TMyModel; (* and here *)): Boolean;
begin
  // Show the dialog
end;

function TMyModelForm.GetSomeUserInput(Sender: TMyModel; (* the params again *)): Boolean;
begin
  // The input can be necessary in different situations - some within a thread, some not.
  if Assigned(FMyThread) then
    Result := FMyThread.GetSomeUserInput(Self, Sender, (* the params *))
  else
    Result := DoGetSomeUserInput(Sender, (* the params *));
end;

你有什么意见吗?

最佳答案

我认为,只要您的长时间运行的转换需要用户交互,您就不会真正对得到的任何答案感到满意。那么让我们先回顾一下:为什么需要中断转换并请求更多信息?这些问题真的是您在开始转型之前无法预料到的吗?用户肯定也对中断不太满意,对吗?他们不能只是开始转型,然后去喝杯咖啡;而是要这样做。他们需要坐下来观察进度条,以防出现问题。呃。

也许转型遇到的问题是可以“保存”到最后的东西。转换是否需要立即知道答案,还是可以完成其他所有事情,然后再做一些“修复”?

关于multithreading - 在长时间任务期间保持应用程序响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/436524/

相关文章:

c++ - 为什么 std::lock_guard/std::unique_lock 不使用类型删除?

delphi - 如何在 freepascal/lazarus 的子进程中实现 cef3 渲染进程处理程序

delphi - 访问泛型类型的成员

jQuery masonry 如何调用layoutComplete

http - Angular 2 : Recursion with Callbacks and REST api calls

javascript - if语句后的jquery回调

c++ - 线程完成后 boost 线程工作对象的重用

java - 如果我不是,谁在调用 Java 线程的 interrupt() 方法?

c# - 有没有办法通过线程名称查询 C# 应用程序中正在运行的线程?

delphi - 如何在嵌入到我的应用程序中的 DLL 中制作表单?