Firemonkey Threading Logic Problem

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Firemonkey Threading Logic Problem

Postby smd » Thu Oct 01, 2015 11:10 pm

RAD Studio 10

My Firemonkey application does some heavy text processing, mostly using a TMemo to handle storage. One part of my program allows the user to open a form that the user can select a variety of text formatting operations. I spent much time carefully testing these routines under every permutation I could ponder. Those routines are well tested.

Earlier today, while testing something else, I opened that form to do a couple quick fixes to the text I was working on. After I clicked one of the buttons, my text disappeared. After a couple hours of single stepping through my code I was not able to make the problem happen while debugging. The text only disappeared when running at full speed.

I finally isolated it and was able to reproduce the problem every time.

The issue is with threading while clearing the clipboard using the following code

Code: Select all
void TEditorForm::ClipboardClear(void)
  {
  if (TPlatformServices::Current->SupportsPlatformService(__uuidof(IFMXClipboardService)))
    {
    _di_IFMXClipboardService Clipboard =
       TPlatformServices::Current->GetPlatformService(__uuidof(IFMXClipboardService));
    Clipboard->SetClipboard(TValue::From<String>(""));
    }
  }


Apparently it starts a thread which took longer to finish (or start executing) than my code that called it. Immediately after calling this function I copy to the clipboard some pre-selected text from a different TMemo. I added the call to clear the clipboard because of an intermittent problem I previously had with old clipboard data mixing with my new copy to clipboard.

My code does not directly create or use threads. All of the threads are created from within the various Firemonkey library routines.

Turns out it the old problem is also the new problem. The new thread created by clearing the clipboard using that function did not finish, or start, before the next instruction in my code which copied the new text to the clipboard. The clear clipboard operation thread then completed, but since my new text was already copied, the old and new was deleted. Apparently there is a threading logic issue in Firemonkey.

I added to the code for clearing the clipboard an Application->ProcessMessages() at the end of the function. This forces everything to catch up before continuing. The problem went away. I played with it for a while. With the ProcessMessages, no error occurred. In fact when I removed the clear clipboard from my code, the old problem of old data sporadically appearing in the clipboard re-appeared.

Where I was using my ClipboardClear function, I replaced with the ProcessMessages function. The old and new problem went away.

So it seems that the problem is that the threading logic in Firemonkey library overloaded operations do not always execute and complete before starting another library overloaded operation thread that uses the result of the first operation. (This is one of several reasons I prefer C over C++) I already figured out that I need to strategically place a ProcessMessages when doing large processing operations that does major editing to large files. Threads tend to stack up faster than they can complete. Now it looks like I need to add even more to force everything to complete before continuing.

Threading can be a complicated issue. apparently the builtin Firemonkey routines do not check if a previously started thread needs to finish before executing. I can see that as being very difficult to implement without prior knowledge of everything.

Is there some pragma or setting I can set that forces certain library routines to not use threading and finish executing before continuing? Effectively that is what I am doing by issuing the ProcessMesaages function, but that means I have to sprinkle that command around in my code.
-----------------------------
Scott
smd
BCBJ Guru
BCBJ Guru
 
Posts: 130
Joined: Sat Nov 29, 2014 8:02 pm
Location: Las Vegas

Re: Firemonkey Threading Logic Problem

Postby rlebeau » Fri Oct 02, 2015 10:06 pm

smd wrote:Apparently it starts a thread which took longer to finish (or start executing) than my code that called it.


IFMXClipboardService does not use threads, and never has. It is synchronous.

That being said, on Android at least, IFMXClipboardService does delegate to the main UI thread when accessing the clipboard from a worker thread, but it blocks the calling thread waiting for that access to finish. So any code that gets/sets text on the clipboard will be serialized across threads, as expected. On other platforms, IFMXClipboardService accesses the clipboard directly, and get/set operations are synchronous.

smd wrote:So it seems that the problem is that the threading logic in Firemonkey library overloaded operations do not always execute and complete before starting another library overloaded operation thread that uses the result of the first operation.


Or maybe you are just using the operations the wrong way to begin with.

smd wrote:(This is one of several reasons I prefer C over C++)


What does that have to do with anything?

smd wrote:I already figured out that I need to strategically place a ProcessMessages when doing large processing operations that does major editing to large files.


You would need that only if you were doing your processing in the context of the main UI thread, where it does not belong in the first place. NEVER block the main UI thread for any noticeable amount of time. The users will not like it. The OS will not like it. So just don't do it.

smd wrote:Threads tend to stack up faster than they can complete. Now it looks like I need to add even more to force everything to complete before continuing.


Or you need to find the real problem, because what you have described about IFMXClipboardService cannot be the culprit. Something else is going on. Your use of ProcessMessages() can cause reentrant issues in code that is not designed to be reentrant, for example.

smd wrote:Threading can be a complicated issue. apparently the builtin Firemonkey routines do not check if a previously started thread needs to finish before executing.


The library does not create internal threads to perform operations. I don't know where you got this idea from.

smd wrote:Is there some pragma or setting I can set that forces certain library routines to not use threading and finish executing before continuing?


No. A pragma would not work anyway. That is a C++ compiler directive. The library is written in Delphi instead.

smd wrote:Effectively that is what I am doing by issuing the ProcessMesaages function


No, it is not. And if you think that is what ProcessMessages() does, you are in worse shape than you think.

smd wrote:but that means I have to sprinkle that command around in my code.


No, you need to write proper code in the first place. Using ProcessMessages() is a band-aid, not a solution.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1532
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA


Return to Technical

Who is online

Users browsing this forum: Google [Bot] and 10 guests

cron