diff --git a/modules/juce_core/system/juce_CompilerSupport.h b/modules/juce_core/system/juce_CompilerSupport.h index 7efab0a8ff..21a3203eec 100644 --- a/modules/juce_core/system/juce_CompilerSupport.h +++ b/modules/juce_core/system/juce_CompilerSupport.h @@ -44,6 +44,7 @@ #if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 #define JUCE_STDLIB_HAS_STD_FUNCTION_SUPPORT 1 + #define JUCE_COMPILER_SUPPORTS_THREAD_LOCAL 1 #endif #ifndef JUCE_EXCEPTIONS_DISABLED @@ -67,6 +68,7 @@ #if (defined (_LIBCPP_VERSION) || ! (JUCE_MAC || JUCE_IOS)) #define JUCE_STDLIB_HAS_STD_FUNCTION_SUPPORT 1 + #define JUCE_COMPILER_SUPPORTS_THREAD_LOCAL 1 #endif #if __has_feature (cxx_generalized_initializers) && (defined (_LIBCPP_VERSION) || ! (JUCE_MAC || JUCE_IOS)) @@ -106,6 +108,7 @@ #define JUCE_COMPILER_SUPPORTS_VARIADIC_TEMPLATES 1 #define JUCE_DELETED_FUNCTION = delete #define JUCE_STDLIB_HAS_STD_FUNCTION_SUPPORT 1 + #define JUCE_COMPILER_SUPPORTS_THREAD_LOCAL 1 #endif #if _MSC_VER >= 1900 diff --git a/modules/juce_core/threads/juce_Thread.cpp b/modules/juce_core/threads/juce_Thread.cpp index 216249a85b..243033e9e1 100644 --- a/modules/juce_core/threads/juce_Thread.cpp +++ b/modules/juce_core/threads/juce_Thread.cpp @@ -277,9 +277,9 @@ bool JUCE_CALLTYPE Process::isRunningUnderDebugger() noexcept return juce_isRunningUnderDebugger(); } -//============================================================================== #if JUCE_UNIT_TESTS +//============================================================================== class AtomicTests : public UnitTest { public: @@ -401,4 +401,60 @@ public: static AtomicTests atomicUnitTests; +//============================================================================== +class ThreadLocalValueUnitTest : public UnitTest, private Thread +{ +public: + ThreadLocalValueUnitTest() + : UnitTest ("ThreadLocalValue"), + Thread ("ThreadLocalValue Thread") + {} + + void runTest() override + { + beginTest ("values are thread local"); + + { + ThreadLocalValue threadLocal; + + sharedThreadLocal = &threadLocal; + + sharedThreadLocal.get()->get() = 1; + + startThread(); + signalThreadShouldExit(); + waitForThreadToExit (-1); + + mainThreadResult = sharedThreadLocal.get()->get(); + + expectEquals (mainThreadResult.get(), 1); + expectEquals (auxThreadResult.get(), 2); + } + + beginTest ("values are per-instance"); + + { + ThreadLocalValue a, b; + + a.get() = 1; + b.get() = 2; + + expectEquals (a.get(), 1); + expectEquals (b.get(), 2); + } + } + +private: + Atomic mainThreadResult, auxThreadResult; + Atomic*> sharedThreadLocal; + + void run() override + { + sharedThreadLocal.get()->get() = 2; + auxThreadResult = sharedThreadLocal.get()->get(); + } +}; + +ThreadLocalValueUnitTest threadLocalValueUnitTest; + #endif diff --git a/modules/juce_core/threads/juce_ThreadLocalValue.h b/modules/juce_core/threads/juce_ThreadLocalValue.h index 64ce6a5b31..3d36c4a14c 100644 --- a/modules/juce_core/threads/juce_ThreadLocalValue.h +++ b/modules/juce_core/threads/juce_ThreadLocalValue.h @@ -22,13 +22,6 @@ #pragma once -// (NB: on win32, native thread-locals aren't possible in a dynamically loaded DLL in XP). -#if ! ((JUCE_MSVC && (JUCE_64BIT || ! defined (JucePlugin_PluginCode))) \ - || (JUCE_MAC && JUCE_CLANG && defined (MAC_OS_X_VERSION_10_7) \ - && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7)) - #define JUCE_NO_COMPILER_THREAD_LOCAL 1 -#endif - //============================================================================== /** Provides cross-platform support for thread-local objects. @@ -61,7 +54,7 @@ public: */ ~ThreadLocalValue() { - #if JUCE_NO_COMPILER_THREAD_LOCAL + #if ! JUCE_COMPILER_SUPPORTS_THREAD_LOCAL for (ObjectHolder* o = first.value; o != nullptr;) { ObjectHolder* const next = o->next; @@ -102,7 +95,10 @@ public: */ Type& get() const noexcept { - #if JUCE_NO_COMPILER_THREAD_LOCAL + #if JUCE_COMPILER_SUPPORTS_THREAD_LOCAL + static thread_local HashMap holder; + return holder.getReference (this); + #else const Thread::ThreadID threadId = Thread::getCurrentThreadId(); for (ObjectHolder* o = first.get(); o != nullptr; o = o->next) @@ -136,12 +132,6 @@ public: while (! first.compareAndSetBool (newObject, newObject->next)); return newObject->object; - #elif JUCE_MAC - static __thread Type object; - return object; - #elif JUCE_MSVC - static __declspec(thread) Type object; - return object; #endif } @@ -150,7 +140,7 @@ public: */ void releaseCurrentThreadStorage() { - #if JUCE_NO_COMPILER_THREAD_LOCAL + #if ! JUCE_COMPILER_SUPPORTS_THREAD_LOCAL const Thread::ThreadID threadId = Thread::getCurrentThreadId(); for (ObjectHolder* o = first.get(); o != nullptr; o = o->next) @@ -166,7 +156,7 @@ public: private: //============================================================================== - #if JUCE_NO_COMPILER_THREAD_LOCAL + #if ! JUCE_COMPILER_SUPPORTS_THREAD_LOCAL struct ObjectHolder { ObjectHolder (const Thread::ThreadID& tid)