开发者

TThread.Synchronize causing (near) deadlock in Delphi 2009 (worked in Delphi 7)

In Delphi 2009, synchronize'd functions that worked fine in Delphi 7 execute with sublime slowness until you wiggle the mouse over the open form. Wiggling the mouse causes the program to go into some mouse idle state which does CheckSynchronize(). CheckSynchronize() appears to be called less frequently in Delphi 2009 than in Delphi 7, but we can't figure out why or where.

Placing this code:

    procedure TMyForm.FormCreate(Sender : TObject)
       Classes.WakeMainThread := WakeMainThread;
    end;

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

Speeds things along at t开发者_运维百科he normal rate. But I get: EAccessViolation in module rtl120.bpl when the thread dies if it's used in a modal app (works fine for a simple dialog utility). I'm guessing 'Classes.WakeMainThread()' is being called just as much as it is in Delphi 7, but sending WM_NULL to application.handle isn't accomplishing anything. I guess it's time to 'get steppin'.


The internals of the Synchronize() mechanism have not changed much between D7 and D2009. Sure, there have been new features added (asynchronous queuing, anonymous methods, etc), but the core implementation to run code in the main thread has not changed. What is more likely happening is something else in your main thread code that you have not shown yet is blocking the main thread from processing pending messages and Synchronize() requests correctly.


TApplication.Create is getting called from another DLL, hence it is waking an invalid handle or some nonsense in that callback.

You need to eliminate statically linked DLLs that include [vcl.]controls.pas because TApplication.Create happens in some initialization code in that unit.

Once you do this, synchronize will be restored to it's former glory.

Unfortunately, fixes you make in one version of Delphi might be undone by changes made in another version of Delphi. So if the problem comes back, go back to the drawing board. Step through the initialization code, specifically the initUnits procedure in system.pas. It runs the initialization code and will bump into vcl.controls.pas eventually and you can peer into the UnitInfo record to find out which file this is being called from.


The best way to fix this is to use the delayed with all your external dlls (at least all your Delphi VCL external DLLs).

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

But this only works in Delphi 2010 and up. Good thing you upgraded to XE2 between the time you asked this question and the time you finally find a satisfying answer to it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜