TThread.Synchronize在Delphi 2009中导致(接近)死锁(在Delphi 7中可运行)

3
在Delphi 2009中,同步执行的函数在Delphi 7中工作正常,但执行速度极慢,直到您在打开的表单上晃动鼠标。晃动鼠标会使程序进入某种鼠标空闲状态,其中会执行CheckSynchronize()。相比于Delphi 7中,CheckSynchronize()似乎在Delphi 2009中被调用得更少,但我们无法弄清原因何在。
将此代码放置在:
    procedure TMyForm.FormCreate(Sender : TObject)
       Classes.WakeMainThread := WakeMainThread;
    end;

    procedure TMyForm.WakeMainThread(Sender: TObject);
    begin 
      SendMessage(Application.MainForm.Handle, WM_NULL, 0, 0);
    end;

正常情况下,事情进展顺利。但是当线程在模态应用程序中死亡时,我收到了rtl120.bpl模块中的EAccessViolation错误(对于简单的对话框实用程序运行良好)。我猜测'Classes.WakeMainThread()'被调用的次数与Delphi 7中一样多,但发送WM_NULL到application.handle并没有实现任何效果。我想是时候“迈出步伐”了。

2个回答

6

Synchronize() 机制的内部实现在 Delphi 7 和 D2009 之间并没有发生太大变化。 当然,也增加了一些新功能(异步排队、匿名方法等),但是在主线程中运行代码的核心实现并没有改变。更有可能的情况是您还没有展示的主线程代码中有其他东西阻止了主线程正确处理挂起的消息和 Synchronize() 请求。


我的编辑有助于回答这个问题吗?我们一直在查找CheckSynchronize函数的调用位置,只有在将wm_null传递给活动窗体时才会调用它,不知何故,在将其传递给应用程序和运行线程的窗体之间存在断开连接。这似乎是发生了变化,可能与MDI子窗体由MDI窗口拥有和通知的方式有关,但我不知道从VCL中开始查找(或如何纠正它)。 - Peter Turner
1
当在主线程上下文中调用TThread.WaitFor()并且主线程消息循环在处理完所有挂起的消息后进入空闲状态时,也会调用CheckSynchronize() - Remy Lebeau
嘿,我觉得你可能已经几年前回答过这个问题,抱歉又翻旧账了。但是,这是否是同样的问题?(为记录起见,他们正在共享RTL bpl) - Peter Turner

4

TApplication.Create被另一个DLL调用,因此它会在该回调函数中唤醒无效的句柄或其他荒谬的东西。

你需要消除静态链接的包含[vcl.]controls.pas的DLL,因为TApplication.Create在该单元中的一些初始化代码中发生。

一旦你这样做了,同步将恢复到它以前的辉煌。

不幸的是,在Delphi的一个版本中所做的修补可能会被另一个版本所更改而撤销。因此,如果问题再次出现,请回到起点。逐步执行初始化代码,特别是system.pas中的initUnits过程。它运行初始化代码,并最终会遇到vcl.controls.pas,然后你可以查看UnitInfo记录,找出哪个文件正在调用它。


解决这个问题的最佳方法是对所有外部dll(至少是所有Delphi VCL外部dll)使用delayed

 function didntknowIusedcontrolsbutIdo() : Integer; external 'useful.dll' delayed;

但这仅适用于Delphi 2010及以上版本。很幸运,在您提出问题和最终找到满意答案之间,您已经升级到了XE2。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接