Jump to content
havrlisan

Creating FMX controls in a background thread

Recommended Posts

24 minutes ago, programmerdelphi2k said:

Ok, but if we use "Create" from Delphi, as it is the default and widely used for this task, and... Delphi calls (uses) the class of this control defined in MSWindows, for example, TEdit uses the definitions from the MSWindows Edit control, so aren't we actually calling a task defined in MSWindows and transferring its owner to Delphi?

No you are not calling a task as in something that will create and run on different thread, you are merely calling a piece of code (function) that will run in the context of your thread.

 

25 minutes ago, programmerdelphi2k said:

OS API thread (performs the actions of a lower level)

There is no separate OS API thread. your application runs in one OS thread. IN terms of OS application is a process. When you run application you are starting a process that will create and run in new thread. but if your application does not explicitly create another thread everything will just run in that one thread, even when you call Windows API.

Share this post


Link to post
22 hours ago, programmerdelphi2k said:

Ok, but if we use "Create" from Delphi, as it is the default and widely used for this task, and... Delphi calls (uses) the class of this control defined in MSWindows, for example, TEdit uses the definitions from the MSWindows Edit control, so aren't we actually calling a task defined in MSWindows and transferring its owner to Delphi?
... that is, an OS API thread (performs the actions of a lower level) transfers to a thread (main) in Delphi (of a higher level)... isn't that what happens?

Create() is just a class constructor.  In runs in the context of whatever thread calls it, like any other class method.  And it does not create any OS window, that happens later.

 

For VCL, all TWinControl-derived UI controls have their own window handle that is created by calling into the OS, and all TGraphicControl-derived UI controls use their parent TWinControl's window.  The creation of that window happens in the context of whatever thread is first to access the window.  IOW the control creates its OS window on an as-needed basis.  However, once it has been created, it is bound to the thread context that created it.  There is no OS thread transferring ownership to a Delphi thread.

 

So, for example, if you create a VCL UI control in the context of the main thread, but the first use of its window is in the context of a worker thread, then the window is bound to the worker thread, not to the main thread.  As such, only the worker thread can receive and dispatch messages for the window, even though the Delphi object that owns the window is in the main thread.

 

For FMX, by default child UI controls do not have their own OS windows at all, only the parent TForm has an OS window.  Child UI controls are designed to act upon, and render themselves inside of, the parent Form's window.  However, this is complicated in recent Delphi versions by the introduction of the ControlType property on various controls, like TEdit. In which case, it is possible for some child UI controls to have a native OS window of their own, which runs on top of the parent Form's window, similar to VCL controls.

Edited by Remy Lebeau

Share this post


Link to post

@Remy Lebeau 

As MSWin is the basis for WinControls, then, I thought that it was "he who created the objects, in fact" (and "Create by Delphi" was just a memory allocator, use see?), and... only later, these objects were offered to Delphi, in this case! Hence, my doubt about who really was the "primary owner" of the object...

But thanks anyway!

Share this post


Link to post
11 hours ago, Dalija Prasnikar said:

Yes, you can have control that completely runs in the different thread that runs its own message loop. That is different scenario from the one I said - constructing the controls in background thread and then using them in main thread. Using (inside main thread) and merely communicating (sending messages are different things. There are boundaries between controls that belong to different threads. In other words there are different levels of thread-safety. Since Windows API has thread affinity, it is not fully thread-safe. 

With this I fully agree.

However, what if we step further to the rabbit hole and place a bg-thread-owned control into a main-thread-owned one? In theory this shouldn't raise issues as long as all interaction is done via Send|PostMessage.

And if we desperately jump into the rabbit hole, we can recall TWinControl.DestroyHandle/CreateHandle that allow to transfer an ownership on a control between threads.

Of course this is really bad practice but what if there's nothing else you can do. F.ex., my colleague has project which periodically  generates charts with thousands of points and exports that to image. And the main UI has to be responsible while generating. Alas, TTeeChart is visual control so he has to use such bad practice creating it inside bg thread.

Share this post


Link to post
17 minutes ago, Fr0sT.Brutal said:

F.ex., my colleague has project which periodically  generates charts with thousands of points and exports that to image. And the main UI has to be responsible while generating. Alas, TTeeChart is visual control so he has to use such bad practice creating it inside bg thread.

I recently did a TeeChart fix to avoid creating its Windows Handle when just drawing it to a image without showing on screen.

 

https://www.steema.com/bugs/show_bug.cgi?id=667

 

We posted a beta yesterday available for download, let me know if your colleague is interested in testing I'll provide a license.

 

regards !

david

 

  • Like 1
  • Thanks 1

Share this post


Link to post
3 minutes ago, Fr0sT.Brutal said:

However, what if we step further to the rabbit hole and place a bg-thread-owned control into a main-thread-owned one? In theory this shouldn't raise issues as long as all interaction is done via Send|PostMessage.

You can do that, but you can only use non-blocking communication. This means SendMessage is out of the question as it can deadlock. This means that your hierarchy of controls must be specifically handled to allow such usage. Which means using Windows API directly for creating such controls.

Any steps into using VCL or FMX to do that are recipe for disaster. Yes, I know that people are doing all kinds of things and that it "works" but they are just being lucky.

 

I am not going to say, yes you can do that when you are out of options, because then people stop and don't look for other options. Another problem is recognizing all thread-safety issues as UI is complex and interactions are also complicated and it is very easy to miss problematic scenarios. Again, they are just being lucky.

 

We need better controls and libraries that can perform heavy tasks outside UI controls and main thread.

Share this post


Link to post
6 hours ago, david berneda said:

We posted a beta yesterday available for download, let me know if your colleague is interested in testing I'll provide a license.

Thanks! I talked to my colleague and he told that that project is working OK, he managed to get things done. But now he's aware of your fix and will decide if he needs it

7 hours ago, Dalija Prasnikar said:

but you can only use non-blocking communication

I see. Child sends message to parent and parent occasionally sends message to child. Oops!

 

  • Like 1

Share this post


Link to post
On 3/16/2023 at 3:36 PM, programmerdelphi2k said:

isn't that what happens?

No. Unless you call an async function, whatever Win32 API you call happens in the thread you are calling it from and then returns.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×