Sync () freezes thread

I am writing a dll library in Delphi with several threads she created. Let me describe the problem step by step. I apologize for the detailed description in advance: - (.

Forget the library for a while. I created a Windows application that will present views from multiple cameras. I created a window that is designed to display a view from a single camera and contains a TImage control. There is a thread (a descendant of the TThread descendants) that downloads the current camera image every couple of milliseconds and assigns it to the TImage control of this window (using the Synchronize () method). The application launches several instances of this window at startup (with a separate thread for each of them), so you can immediately view the live view from multiple cameras. What's more, all viewports are parents of the main application window, so they appear inside it.

Everything worked fine until I decided to put these two windows in the dll library. I just found it necessary for some reason, but now they are not important. Therefore, I created a new dll library, added an existing main window and a camera viewing window to the project, and exported a function that creates and returns an instance of the main window. When the main window is created, it creates several windows with a camera viewing window, which makes them parents.

Then, for testing purposes, I created an application that imports the above dll function from the library and calls it at startup to get an instance of the main window; then just shows it on the screen (in a non-modal state).

When I launched the application, it turned out that I could not get a single image from any camera. When I debugged it, I noticed that when a thread calls the Synchronize () method, it hangs forever. This did not happen before setting both of these windows in the dll.

And that is my problem. Honestly, this is my first approach to libraries with which I had to overcome many other problems. You may wonder why I use windows instead of frames ... Therefore, whenever I created an instance of TFrame in the dll, I would get an exception saying: "The xxx control does not have a parent window." I did not know what to do with this, so instead I used windows: - (.

Could you tell me what to do with the synchronization problem? The main thread does not seem to be blocked when the application is running, it accepts push buttons, etc. What is the problem?

Please, help!

Thanks in advance!

+6
multithreading dll delphi
source share
3 answers

When TThread.Synchronize called TThread.Synchronize the thread and method pointer are added to the global SyncList: TList in Classes.pas. Basically, the exe TApplication.Idle usual calls to CheckSynchronize , which checks the SyncList , but checks the version in exe instead of the one in the DLL. The end result, your synchronized methods are never called.

The easiest solution would be to move from the DLL to the packages, which will eliminate the duplicate of SyncList .

Another approach would be to override the exe Application.OnIdle callback and call your CheckSynchronize DLL manually. To do this, you will need some help from the application, since your DLL will have an Application object and this will not work.

+13
source share

It’s a bad idea to use Synchronize because it leads to such race conditions. I don’t know what is going on specifically in your code β€” it’s hard to say without seeing any code β€” but this problem is actually quite common.

Exchange between threads is best done using a queue. If you have the latest version, Delphi XE, there is a TThreadedQueue<T> class in Generics.Collections , which is perfect for this kind of thing. Pass 0 to the PopTimeout parameter in the constructor, ask your camera threads to click images, and ask your main thread to poll queues with the third PopItem overload, for example:

 var CurrentItem: TImage; begin if ThreadQueue.PopItem(CurrentItem) = wrSignaled then UpdateImage(CurrentItem); //or however you do it end; 

(If there is nothing in the queue, PopItem will return wrTimeout instead.)

If you do not have Delphi XE, you need to create your own thread-safe queue or find it from a third-party source, for example Primoz Gabrielcic's OmniThreadLibrary.

+2
source share

I found two ways to solve Synchronize() by hanging a thread (in Delphi 7):

  • Put a TTimer in the Dll form and onTimer call the CheckSynchronize event;

procedure TPluginForm.Timer1Timer(Sender: TObject); begin CheckSynchronize; end;

  1. Add this module to the Dll form usage section.
0
source share

All Articles