【问题标题】:What is the best way to call a procedure "delayed"?将程序称为“延迟”的最佳方式是什么?
【发布时间】:2009-02-25 21:58:36
【问题描述】:

有两个过程,A1 和 A2,它们都在代码中调用函数 B:

function B: boolean;
begin
  // do other stuff
end;

procedure A1;
begin
  // do stuff
  if b then
    ...
  // do stuff
end;

procedure A2;
begin
  // do stuff
  if b then
    A1; // <- how to call A1 "delayed"?
  // do stuff
end;

如果 A2 中的条件为真,则必须调用过程 A1,但这会在 A2 仍在运行时发生,这是我不希望的。

应该发生的是: 如果 A2 中的条件为真,则 A2 应该结束,离开 A2 后应该调用过程 A1。

一个丑陋的解决方案是设置一个计时器,在确保 A2 完成的延迟后调用 A1。

但一定有更好的方法,对吧?

编辑:在我的例子中,A1 和 A2 是事件,所以它们不是由代码调用的,我不能在 A2 完成后从调用过程中调用 A1。

【问题讨论】:

    标签: delphi


    【解决方案1】:

    鉴于您的限制,听起来您想在返回之前将PostMessage 作为A2 中的最后一件事。应该设置PostMessage 参数以便触发A1 事件。唯一需要担心的是竞争条件,但我不确定这会是 Windows 消息队列的问题。

    【讨论】:

    • 我不相信会有竞争条件。 PostMessage 是要走的路。一旦 A2 事件处理程序完成或手动调用 Application.ProcessMessags,就会处理消息队列。
    【解决方案2】:

    我过去通过创建延迟方法调用单元处理过类似的问题。如果您只需要在一个地方使用它可能有点过头了,但拥有它是一件有用的事情。

    就我而言,我会写

    procedure A2;
    begin
      // do stuff
      if b then
        DelayedCall('A1' {identifier}, A1 {event}, 0 {ms delay}, [] {various function flags}); 
      // do stuff
    end;
    

    Internally DelayedCall 将 A1 置于有序列表中(按到期时间排序)。计时器轮询列表(以可变频率取决于第一个事件的到期时间)并运行任何到期事件。

    这不是一个非常复杂的函数,但它可能非常有用。

    编辑: 在提供的示例中,使用 PostMessage 会运行得更快。 DelayedCall 直到 A2 完成后才会运行(除非 A2 在其中有 ProcessMessages 或 Sleep 调用),但它可能不会在 A2 完成后立即运行,具体取决于其他情况。但是,我自己经常在类似的场景中使用 DelayedCall。

    PostMessage 和 DelayedCall 都不会立即发生,它们都需要等待消息循环被检查

    【讨论】:

    • 使用计时器的问题是您永远不知道系统中还发生了什么以及 A2 何时完成。 PostMessage 会将调用放在事件 A2 的末尾,下次处理消息队列时。
    【解决方案3】:

    您可以使用布尔标志:如果 A2 正在运行,则设置“A1_should_run”,并检查 A2 末尾的标志。这个解决方案很简单,但有点难看,因为它在代码中添加了非局部性,并且不能很好地适用于更复杂的情况。

    您可以使用调用队列:A1 和 A2 始终通过放置在队列中来运行,在这种情况下,您只需将 A1 加入队列即可。对于您的情况,此解决方案并不那么简单,但非常适用于更复杂的情况。

    【讨论】:

      猜你喜欢
      • 2015-04-24
      • 2012-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-27
      • 2013-05-29
      • 1970-01-01
      • 2021-03-10
      相关资源
      最近更新 更多