Uhh…not sure what you mean. The static CriticalSection in the function RunningThreadsList::getInstance() is definitely not thread-safe. If two threads get into getInstance() at the same time, it is vulnerable to double construction. I can give you a test case if you want, but it’s really simple. Just create 100 juce Threads in a tight loop from main(). When they get destroyed, there will be an assertion about the thread not being found in the running threads list (because one or more of them went into a different list, from the double construction).
So…RunningThreadsList::getInstance(), is not thread safe on all environments (note that gcc versions 4.0 and later fix this problem, while visual studio 2008 does not).
(That's assuming you don't have any other static constructors that use the CriticalSection before its static initialiser has been run)
Well that’s exactly my problem! I have implemented a singleton that makes its own thread to signal a periodic garbage collection, and I have another object with static storage duration that implements a fixed memory allocator. The allocator tries to access the singleton, which exposes me to order-of-initialization issues.
But this is orthogonal to the juce::Thread issue (in my own singleton implementation, I use a StaticCriticalSection to ensure thread safety).
To summarize, juce::RunningThreadsList::getInstance() is not thread safe, and this can be demonstrated by creating a bunch of juce::Thread in a tight loop, then terminating all of them. If it seems like this is not a problem on the Mac, well that’s because gcc 4.0 and later invisibly add the necessary “two-bool atomic initialization” that I have manually coded out in my StaticCriticalSection (and this behavior can be disabled with the -fno-threadsafe-statics flag).
My fix to juce_Thread.cpp, assuming that you have the StaticObject and StaticCriticalSection classes, is the following:
class RunningThreadsList
{
public:
static StaticCriticalSection s_lock;
//...
static RunningThreadsList& getInstance()
{
// protect the "invisible bool" added by some compilers
StaticCriticalSection::ScopedLock lock_ (s_lock);
{
static RunningThreadsList runningThreads;
return runningThreads;
}
}
//...
};
StaticCriticalSection RunningThreadsList::s_lock;
As a side note, juce_DeclareSingleton is vulnerable to order of initialization issues because _singletonLock requires the constructor execute in order to function correctly. Unlike the problem with function-scope objects with static storage duration, that will not be solved by C++0x, but is solved using StaticCriticalSection.