Application taking a really long time to synch threads ( or not at all )
Asked Answered
F

1

16

I am using REST components in Delphi XE5 (iOS and Android). I am testing via the iOS simulator currently, and my application often hangs at the following line within my code:

R_Request.Execute;

After some debugging, I find it it specifically hangs at this line of code within the REST.Client.PAS:

HandleEvent(DoAfterExecute);

which looks like:

procedure TCustomRESTRequest.HandleEvent(AEventHandler: TMethod);
begin
  // Handle Synchronized if we are NOT already in the main thread
  // NEVER call synchronize on the MainThread - that might shift the island!
  if SynchronizedEvents and (System.MainThreadID <> TThread.CurrentThread.ThreadID) then
    TThread.Synchronize(TThread.CurrentThread, AEventHandler) // FAILS HERE
  else
    AEventHandler;
end;

It's either NOT returning the thread in the .Synchronize or taking an extremely long time ( 5 minutes or so ) ... It worked once while debugging, but has not ever since and again just now ( 30 min later, and after letting it set for 5 minutes to return a thread).

Help ? Or at least any sense of direction anyone can give me?

Again, developing for iOS and Android ( so FMX... ) and currently testing via iOS simulator. Thanks !

Ferguson answered 14/4, 2014 at 21:32 Comment(0)
L
21

The problem is that TThread.Synchronize() is broken in FireMonkey. See this QC report:

Report #123579: TThread.Synchronize() and TThread.Queue() do not work correctly in FireMonkey

This has only just recently been discovered, but it has been broken since FireMonkey was first introduced and nobody apparently noticed until now.

Until Embarcadero fixes it, try calling CheckSynchronize() periodically in the main thread, such as in a timer.

Lenee answered 14/4, 2014 at 21:35 Comment(11)
Yup, I was shocked when I found it, and there is no good way to manually implement WakeMainThread() to "wake up" the main thread in a cross-platform manner because different platforms handle main thread event queues differently. At least CheckSynchronize() itself is cross-platform, but getting the RTL to call it is a PITA unless you call it yourself.Lenee
Womp! Thanks though for the CheckSynch. suggestion.Ferguson
@Hans, Is it really solved? Because when I try to do in an TThread.Execute scope this self.Synchronize(procedure begin BusyForm.Show end); on android it returns awful exeception CalledFromWrongThreadException: Only the original thread that created a view hierarcy can touch its views which is suggested to solve in Android Studio with running UI updates with runOnUiThread method. Which means, that it is still broken in XE8. Any remarks are appreciated.Candlelight
@Candlelight that is a completely different issue. Synchronize() itself is fixed now so it executes the user's function. What you are experiencing is a new issue related to the fact that the FMX main thread and the Android UI thread are not always the same thread! This is planned to be addressed in the next Delphi version. In the meantime, the FMX.Platform.Android.TPlatformAndroid class has some methods for executing functions via runOnUIThread().Lenee
@RemyLebeau, thanks for the tip. If you dont mind to give a bit more details - does that mean, that the best solution is to {IFDEF} whole Threaded class for ANDROID and the rest of the platforms? Or do you mean that its replace only Synchronize calls in the code with runInUIThread() one?Candlelight
@Candlelight just the latter, and only for synced code that absolutely must run in the real UI thread, and not just synced in general. Otherwise, consider changing the thread code to not have to touch the UI directly at all.Lenee
@RemyLebeau, that's inspiring. My point is to have a Custom Overlay (BusyBox) to show whenever background threaded task arises. First I thought that the BusyBox could be shown from a task-thread, but now I guess it is more effective to have separate BusyBox-thread that would manage "platformed"-sync for the box and would get notifications from task-threads for that. Is there any other problems that could be met with that plan, ie, in other platforms like MACOS, IOS?Candlelight
@Candlelight on every platform, UI management should always be separate from task management. Only the main UI thread should manage the UI, and worker threads should manage only their background tasks. Use inter-thread communications to going back and forth as needed.Lenee
@RemyLebeau, so do you actually suggest to add an additional message, that would respond to wm_showbusy in app thread with a call to Android specific method, or it just fits anyway and would run in main-platform-thread? Or a separate thread for this special task is also fits?Candlelight
@RemyLebeau, my issue is sovled pretty simple. As to TPlatformAndroid which is hidden in implementation section of the unit, but gives some thoughts to think (I guess its possible to solve the problem on the cross-platform basis), I found a nice proc CallInUIThreadAndWaitFinishing inside FMX.Android.Helpers which do the trick. So I have to {$IFDEF} only. As always, Im open-minded for remarks.Candlelight
Im sorry, I cant edit my last post, but correct unit path for XE8 is FMX.Helpers.AndroidCandlelight

© 2022 - 2024 — McMap. All rights reserved.