123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- /*
- ==============================================================================
- This file is part of the juce_core module of the JUCE library.
- Copyright (c) 2015 - ROLI Ltd.
- Permission to use, copy, modify, and/or distribute this software for any purpose with
- or without fee is hereby granted, provided that the above copyright notice and this
- permission notice appear in all copies.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
- TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
- NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
- IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ------------------------------------------------------------------------------
- NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
- All other JUCE modules are covered by a dual GPL/commercial license, so if you are
- using any other modules, be sure to check that you also comply with their license.
- For more details, visit www.juce.com
- ==============================================================================
- */
- #ifndef JUCE_THREADLOCALVALUE_H_INCLUDED
- #define JUCE_THREADLOCALVALUE_H_INCLUDED
- // (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.
- This class holds an internal list of objects of the templated type, keeping
- an instance for each thread that requests one. The first time a thread attempts
- to access its value, an object is created and added to the list for that thread.
- Typically, you'll probably want to create a static instance of a ThreadLocalValue
- object, or hold one within a singleton.
- The templated class for your value must be a primitive type, or a simple POD struct.
- When a thread no longer needs to use its value, it can call releaseCurrentThreadStorage()
- to allow the storage to be re-used by another thread. If a thread exits without calling
- this method, the object storage will be left allocated until the ThreadLocalValue object
- is deleted.
- */
- template <typename Type>
- class ThreadLocalValue
- {
- public:
- /** */
- ThreadLocalValue() noexcept
- {
- }
- /** Destructor.
- When this object is deleted, all the value objects for all threads will be deleted.
- */
- ~ThreadLocalValue()
- {
- #if JUCE_NO_COMPILER_THREAD_LOCAL
- for (ObjectHolder* o = first.value; o != nullptr;)
- {
- ObjectHolder* const next = o->next;
- delete o;
- o = next;
- }
- #endif
- }
- /** Returns a reference to this thread's instance of the value.
- Note that the first time a thread tries to access the value, an instance of the
- value object will be created - so if your value's class has a non-trivial
- constructor, be aware that this method could invoke it.
- */
- Type& operator*() const noexcept { return get(); }
- /** Returns a pointer to this thread's instance of the value.
- Note that the first time a thread tries to access the value, an instance of the
- value object will be created - so if your value's class has a non-trivial
- constructor, be aware that this method could invoke it.
- */
- operator Type*() const noexcept { return &get(); }
- /** Accesses a method or field of the value object.
- Note that the first time a thread tries to access the value, an instance of the
- value object will be created - so if your value's class has a non-trivial
- constructor, be aware that this method could invoke it.
- */
- Type* operator->() const noexcept { return &get(); }
- /** Assigns a new value to the thread-local object. */
- ThreadLocalValue& operator= (const Type& newValue) { get() = newValue; return *this; }
- /** Returns a reference to this thread's instance of the value.
- Note that the first time a thread tries to access the value, an instance of the
- value object will be created - so if your value's class has a non-trivial
- constructor, be aware that this method could invoke it.
- */
- Type& get() const noexcept
- {
- #if JUCE_NO_COMPILER_THREAD_LOCAL
- const Thread::ThreadID threadId = Thread::getCurrentThreadId();
- for (ObjectHolder* o = first.get(); o != nullptr; o = o->next)
- if (o->threadId == threadId)
- return o->object;
- for (ObjectHolder* o = first.get(); o != nullptr; o = o->next)
- {
- if (o->threadId == nullptr)
- {
- {
- SpinLock::ScopedLockType sl (lock);
- if (o->threadId != nullptr)
- continue;
- o->threadId = threadId;
- }
- o->object = Type();
- return o->object;
- }
- }
- ObjectHolder* const newObject = new ObjectHolder (threadId);
- do
- {
- newObject->next = first.get();
- }
- 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
- }
- /** Called by a thread before it terminates, to allow this class to release
- any storage associated with the thread.
- */
- void releaseCurrentThreadStorage()
- {
- #if JUCE_NO_COMPILER_THREAD_LOCAL
- const Thread::ThreadID threadId = Thread::getCurrentThreadId();
- for (ObjectHolder* o = first.get(); o != nullptr; o = o->next)
- {
- if (o->threadId == threadId)
- {
- SpinLock::ScopedLockType sl (lock);
- o->threadId = nullptr;
- }
- }
- #endif
- }
- private:
- //==============================================================================
- #if JUCE_NO_COMPILER_THREAD_LOCAL
- struct ObjectHolder
- {
- ObjectHolder (const Thread::ThreadID& tid)
- : threadId (tid), next (nullptr), object()
- {}
- Thread::ThreadID threadId;
- ObjectHolder* next;
- Type object;
- JUCE_DECLARE_NON_COPYABLE (ObjectHolder)
- };
- mutable Atomic<ObjectHolder*> first;
- SpinLock lock;
- #endif
- JUCE_DECLARE_NON_COPYABLE (ThreadLocalValue)
- };
- #endif // JUCE_THREADLOCALVALUE_H_INCLUDED
|