Is the following line a race condition between the OpenGL thread and the JUCE MessageThread?
In the file juce/examples/GUI/OpenGLDemo.h
, line 848 (in develop branch), in the function renderOpenGL()
:
glViewport (0, 0, roundToInt (desktopScale * (float) getWidth()), roundToInt (desktopScale * (float) getHeight()));
This line accesses juce::Component
methods, getWidth()
and getHeight()
while running on the OpenGL thread via the renderOpenGL()
callback.
I set a breakpoint here and went back in the stack trace to OpenGLContext.cpp -> renderFrame()
and I saw that the MessageManager::Lock
, mmLock
local variable had its member lockWasSuccessful
set to false, meaning that the OpenGL thread is not holding a Message Thread lock when accessing Component
data. The Component
data could simultaneously be modified by the MessageThread, causing a race condition.
The screenshots below show what I saw in the debugger.
In the past, it was my understanding that the OpenGL thread always holds a MessageManager::Lock
in the renderOpenGL()
callback. But, this is not always true. The OpenGL thread only holds a MessageManager::Lock
when the associated OpenGLContext
is attached to render juce::Components
, not purely GL code, and any of those Components
are marked to be redrawn by the GL thread. If no Components
need to be redrawn, and there is other rendering being done by the GL thread in a renderOpenGL()
callback, then the GL thread will not be holding a MessageManager::Lock
.
I learned this from this post: OpenGL Thread MessageManager Lock - #4 by fr810
Lastly, I see, also in OpenGLDemo.h
line 679 (develop branch), a MessageManagerLock
is requested before running a bit of code on the GL thread:
const MessageManagerLock mml (ThreadPoolJob::getCurrentThreadPoolJob());
if (! mml.lockWasGained())
return false;
g.drawFittedText (String (Time::getCurrentTime().getMilliseconds()), image.getBounds(), Justification::centred, 1);
I am not sure why this particular code is guarded by the lock while many Graphics
calls above, for an Image
, are not guarded. (I am not entirely sure which JUCE methods/objects are unsafe to access on a thread other than the Message Thread.)
If I were to access juce Message Thread data in a renderOpenGL()
callback, should I request a MessageManagerLock in the same fashion?
const MessageManagerLock mml (ThreadPoolJob::getCurrentThreadPoolJob());
if (! mml.lockWasGained())
return false;
Thanks for any help and clarity on this topic!