HEADS-UP: Threading restriction for Animation play, pause, stop now enforced USE CASE

John Hendrikx john.hendrikx at gmail.com
Tue Jan 23 16:36:16 UTC 2024


On 23/01/2024 16:56, Jurgen Doll wrote:
> Hi John and others,
>
> I don't think we are entirely on the same page, so here's the objective.
>
> The Goal: To determine if the FX animation thread and a SINGLE other 
> thread can access Animation in a safe manner wrt play, stop, and resume.
The number of threads is irrelevant really, it's either thread safe or 
it isn't.
>
> Non Goal: Multi-threaded access of Animation play, stop, and resume is 
> NOT a goal.
>
> Wrt play() and resume(), it is ALWAYS safe to call them on a 
> background thread because at this point the Animation isn't being 
> processed by the FX thread as the "Animation" isn't contained in the 
> AbstractPrimaryTimer receivers array.

I'm afraid that is incorrect.  The fact that your animation is not 
running doesn't mean that AbstractPrimaryTimer isn't in use by other 
animations that are running.  These other animations are using the 
receivers array, and may be modifying it or reading from it from the FX 
thread.

When you start your animation on a different thread, you are accessing 
these fields with a different thread, and modifying them.  Since the JVM 
is free to cache values and do other fancy things (like reordering 
read/writes) in the absence of synchronized/locking, there is no 
guarantee that the FX thread will see those modifications until these 
are flushed to main memory (or caches are synced).  Even then, the FX 
thread may have these values cached somewhere, and so it may not go all 
the way to main memory to see if its assumptions are now incorrect.  The 
only way to ensure this is with proper use of synchronization.

So a hypothetical scenario:

- AbstractPrimaryTimer has no receivers
- A receiver is added via the FX thread, slot 0 is now filled and 
receiversLength is now 1.  Due to cache lines being large, it also read 
slot 1 (which is null)
- You start your animation on another thread.  Since you didn't see the 
receivers array yet, you may see one of these states:
     - The change from the FX thread was flushed to main memory, and you 
see [X, null] and receiversLength = 1
     - The change from the FX thread was partially flushed, and you see 
[X, null]  and receiversLength = 0 (!!)
     - Nothing was flushed yet, and you see [null, null] and 
receiversLength = 0

Now, you can see that it would be very dangerous to proceed to modify 
the array based on half flushed information.  Something similar happens 
when you are the first to start an animation, and then another is 
started later.  If the changes of your thread are not flushed yet (or 
partially) then the FX thread will act on partially flushed data, or 
even see no receivers yet at all...

--John

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20240123/b75a2c23/attachment.htm>


More information about the openjfx-dev mailing list