mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Fixed a bug where ThreadLocalValue would inadvertently share its value between different instances of the same Type
This commit is contained in:
parent
71ee795bbb
commit
41f7835119
3 changed files with 67 additions and 18 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<int> 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<int> a, b;
|
||||
|
||||
a.get() = 1;
|
||||
b.get() = 2;
|
||||
|
||||
expectEquals (a.get(), 1);
|
||||
expectEquals (b.get(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Atomic<int> mainThreadResult, auxThreadResult;
|
||||
Atomic<ThreadLocalValue<int>*> sharedThreadLocal;
|
||||
|
||||
void run() override
|
||||
{
|
||||
sharedThreadLocal.get()->get() = 2;
|
||||
auxThreadResult = sharedThreadLocal.get()->get();
|
||||
}
|
||||
};
|
||||
|
||||
ThreadLocalValueUnitTest threadLocalValueUnitTest;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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<const void*, Type> 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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue