27 : threadName (name), threadStackSize (
stackSize)
33 if (deleteOnThreadEnd)
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;
84 if (threadName.isNotEmpty())
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);
151 threadPriority = priority;
162 return threadHandle.
get() !=
nullptr;
167 return getCurrentThreadHolder()->value.get();
172 return threadId.
get();
179 listeners.call ([] (
Listener&
l) {
l.exitSignalSent(); });
184 return shouldExit.
get() != 0;
238 threadHandle =
nullptr;
249 listeners.
add (listener);
254 listeners.
remove (listener);
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)
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");
405 beginTest (
"Atomic void*");
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,
487 : UnitTest (
"ThreadLocalValue", UnitTestCategories::threads),
488 Thread (
"ThreadLocalValue Thread")
491 void runTest()
override
493 beginTest (
"values are thread local");
503 signalThreadShouldExit();
504 waitForThreadToExit (-1);
512 beginTest (
"values are per-instance");
520 expectEquals (
a.get(), 1);
521 expectEquals (
b.get(), 2);
536ThreadLocalValueUnitTest threadLocalValueUnitTest;
void remove(int indexToRemove)
void add(const ElementType &newElement)
static JUCE_CONSTEXPR uint16 swap(uint16 value) noexcept
static void JUCE_CALLTYPE writeToLog(const String &message)
static bool JUCE_CALLTYPE isRunningUnderDebugger() noexcept
void enter() const noexcept
bool tryEnter() const noexcept
GenericScopedLock< SpinLock > ScopedLockType
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