27 : threadName (name), threadStackSize (stackSize)
33 if (deleteOnThreadEnd)
53 CurrentThreadHolder() noexcept {}
55 using Ptr = ReferenceCountedObjectPtr<CurrentThreadHolder>;
56 ThreadLocalValue<Thread*> value;
58 JUCE_DECLARE_NON_COPYABLE (CurrentThreadHolder)
61static char currentThreadHolderLock [
sizeof (SpinLock)];
63static SpinLock* castToSpinLockWithoutAliasingWarning (
void* s)
65 return static_cast<SpinLock*
> (s);
68static CurrentThreadHolder::Ptr getCurrentThreadHolder()
70 static CurrentThreadHolder::Ptr currentThreadHolder;
73 if (currentThreadHolder ==
nullptr)
74 currentThreadHolder =
new CurrentThreadHolder();
76 return currentThreadHolder;
79void Thread::threadEntryPoint()
81 const CurrentThreadHolder::Ptr currentThreadHolder (getCurrentThreadHolder());
82 currentThreadHolder->value =
this;
87 if (startSuspensionEvent.
wait (10000))
91 if (affinityMask != 0)
104 currentThreadHolder->value.releaseCurrentThreadStorage();
108 auto shouldDeleteThis = deleteOnThreadEnd;
111 if (shouldDeleteThis)
116void JUCE_API juce_threadEntryPoint (
void* userData)
118 static_cast<Thread*
> (userData)->threadEntryPoint();
128 if (threadHandle.
get() ==
nullptr)
131 setThreadPriority (threadHandle.
get(), threadPriority);
132 startSuspensionEvent.
signal();
140 if (threadHandle.
get() ==
nullptr)
142 auto isRealtime = (priority == realtimeAudioPriority);
145 isAndroidRealtimeThread = isRealtime;
151 threadPriority = priority;
162 return threadHandle.
get() !=
nullptr;
167 return getCurrentThreadHolder()->value.
get();
172 return threadId.
get();
184 return shouldExit.
get() != 0;
190 return currentThread->threadShouldExit();
226 if (timeOutMilliseconds != 0)
238 threadHandle =
nullptr;
249 listeners.add (listener);
254 listeners.remove (listener);
260 bool isRealtime = (newPriority == realtimeAudioPriority);
275 jassert (
isThreadRunning() && (isRealtime == isAndroidRealtimeThread));
277 isAndroidRealtimeThread = isRealtime;
282 threadPriority = newPriority;
291 return setThreadPriority ({}, newPriority);
296 affinityMask = newAffinityMask;
302 return defaultEvent.
wait (timeOutMilliseconds);
311struct LambdaThread :
public Thread
313 LambdaThread (std::function<
void()> f) :
Thread (
"anonymous"), fn (f) {}
321 std::function<void()> fn;
323 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LambdaThread)
328 auto anon =
new LambdaThread (functionToRun);
329 anon->deleteOnThreadEnd =
true;
338 for (
int i = 20; --i >= 0;)
350 return juce_isRunningUnderDebugger();
362 :
UnitTest (
"Atomics", UnitTestCategories::threads)
365 void runTest()
override
370 expect (numElementsInArray(a1) == 7);
372 expect (numElementsInArray(a2) == 3);
376 expect (
ByteOrder::swap ((uint64) 0x1122334455667788ULL) == 0x8877665544332211LL);
378 beginTest (
"Atomic int");
379 AtomicTester <int>::testInteger (*this);
380 beginTest (
"Atomic unsigned int");
381 AtomicTester <unsigned int>::testInteger (*this);
382 beginTest (
"Atomic int32");
383 AtomicTester <int32>::testInteger (*this);
384 beginTest (
"Atomic uint32");
385 AtomicTester <uint32>::testInteger (*this);
386 beginTest (
"Atomic long");
387 AtomicTester <long>::testInteger (*this);
388 beginTest (
"Atomic int*");
389 AtomicTester <int*>::testInteger (*this);
390 beginTest (
"Atomic float");
391 AtomicTester <float>::testFloat (*this);
392 #if ! JUCE_64BIT_ATOMICS_UNAVAILABLE
393 beginTest (
"Atomic int64");
394 AtomicTester <int64>::testInteger (*this);
395 beginTest (
"Atomic uint64");
396 AtomicTester <uint64>::testInteger (*this);
397 beginTest (
"Atomic double");
398 AtomicTester <double>::testFloat (*this);
400 beginTest (
"Atomic pointer increment/decrement");
401 Atomic<int*> a (a2);
int* b (a2);
405 beginTest (
"Atomic void*");
406 Atomic<void*> atomic;
409 atomic.set ((
void*) 10);
412 expect (atomic.value == c);
413 expect (atomic.get() == c);
417 template <
typename Type>
423 static void testInteger (UnitTest& test)
431 test.expect (a.value == c);
432 test.expect (a.get() == c);
436 test.expect (a.get() == c);
441 test.expect (a.get() == c);
443 test.expect (++a == ++c);
446 test.expect (--a == --c);
447 test.expect (a.get() == c);
455 static void testFloat (UnitTest& test)
464 test.expect (a.get() == (Type) 101);
465 test.expect (! a.compareAndSetBool ((Type) 300, (Type) 200));
466 test.expect (a.get() == (Type) 101);
467 test.expect (a.compareAndSetBool ((Type) 200, a.get()));
468 test.expect (a.get() == (Type) 200);
470 test.expect (a.exchange ((Type) 300) == (Type) 200);
471 test.expect (a.get() == (Type) 300);
474 test.expect (b.get() == a.get());
479static AtomicTests atomicUnitTests;
482class ThreadLocalValueUnitTest :
public UnitTest,
486 ThreadLocalValueUnitTest()
487 : UnitTest (
"ThreadLocalValue", UnitTestCategories::threads),
488 Thread (
"ThreadLocalValue Thread")
491 void runTest()
override
493 beginTest (
"values are thread local");
496 ThreadLocalValue<int> threadLocal;
498 sharedThreadLocal = &threadLocal;
500 sharedThreadLocal.get()->get() = 1;
503 signalThreadShouldExit();
504 waitForThreadToExit (-1);
506 mainThreadResult = sharedThreadLocal.get()->get();
508 expectEquals (mainThreadResult.get(), 1);
509 expectEquals (auxThreadResult.get(), 2);
512 beginTest (
"values are per-instance");
515 ThreadLocalValue<int> a, b;
520 expectEquals (a.get(), 1);
521 expectEquals (b.get(), 2);
526 Atomic<int> mainThreadResult, auxThreadResult;
527 Atomic<ThreadLocalValue<int>*> sharedThreadLocal;
531 sharedThreadLocal.get()->get() = 2;
532 auxThreadResult = sharedThreadLocal.get()->get();
536ThreadLocalValueUnitTest threadLocalValueUnitTest;
static JUCE_CONSTEXPR uint16 swap(uint16 value) noexcept
static void JUCE_CALLTYPE writeToLog(const String &message)
static bool JUCE_CALLTYPE isRunningUnderDebugger() noexcept
ReferencedType * get() const noexcept
void enter() const noexcept
bool tryEnter() const noexcept
GenericScopedLock< SpinLock > ScopedLockType
bool isNotEmpty() const noexcept
virtual void exitSignalSent()=0
bool setPriority(int priority)
void setAffinityMask(uint32 affinityMask)
static void JUCE_CALLTYPE setCurrentThreadAffinityMask(uint32 affinityMask)
static void JUCE_CALLTYPE sleep(int milliseconds)
static Thread *JUCE_CALLTYPE getCurrentThread()
bool wait(int timeOutMilliseconds) const
ThreadID getThreadId() const noexcept
bool waitForThreadToExit(int timeOutMilliseconds) const
static void JUCE_CALLTYPE setCurrentThreadName(const String &newThreadName)
Thread(const String &threadName, size_t threadStackSize=0)
static bool currentThreadShouldExit()
bool threadShouldExit() const
static void JUCE_CALLTYPE yield()
static ThreadID JUCE_CALLTYPE getCurrentThreadId()
bool stopThread(int timeOutMilliseconds)
void addListener(Listener *)
void signalThreadShouldExit()
static bool setCurrentThreadPriority(int priority)
bool isThreadRunning() const
void removeListener(Listener *)
static void launch(std::function< void()> functionToRun)
static uint32 getMillisecondCounter() noexcept
bool wait(int timeOutMilliseconds=-1) const
Type get() const noexcept