2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../core/juce_StandardHeader.h"
30 #include "juce_Thread.h"
31 #include "juce_SpinLock.h"
32 #include "../core/juce_Time.h"
33 #include "../containers/juce_Array.h"
36 //==============================================================================
37 class RunningThreadsList
46 // Some threads are still running! Make sure you stop all your
47 // threads cleanly before your app quits!
48 jassert (threads
.size() == 0);
51 void add (Thread
* const thread
)
53 const SpinLock::ScopedLockType
sl (lock
);
54 jassert (! threads
.contains (thread
));
58 void remove (Thread
* const thread
)
60 const SpinLock::ScopedLockType
sl (lock
);
61 jassert (threads
.contains (thread
));
62 threads
.removeValue (thread
);
65 int size() const noexcept
67 return threads
.size();
70 Thread
* getThreadWithID (const Thread::ThreadID targetID
) const noexcept
72 const SpinLock::ScopedLockType
sl (lock
);
74 for (int i
= threads
.size(); --i
>= 0;)
76 Thread
* const t
= threads
.getUnchecked(i
);
78 if (t
->getThreadId() == targetID
)
85 void stopAll (const int timeOutMilliseconds
)
87 signalAllThreadsToStop();
91 Thread
* firstThread
= getFirstThread();
93 if (firstThread
!= nullptr)
94 firstThread
->stopThread (timeOutMilliseconds
);
100 static RunningThreadsList
& getInstance()
102 static RunningThreadsList runningThreads
;
103 return runningThreads
;
107 Array
<Thread
*> threads
;
110 void signalAllThreadsToStop()
112 const SpinLock::ScopedLockType
sl (lock
);
114 for (int i
= threads
.size(); --i
>= 0;)
115 threads
.getUnchecked(i
)->signalThreadShouldExit();
118 Thread
* getFirstThread() const
120 const SpinLock::ScopedLockType
sl (lock
);
121 return threads
.getFirst();
126 //==============================================================================
127 void Thread::threadEntryPoint()
129 RunningThreadsList::getInstance().add (this);
133 if (threadName_
.isNotEmpty())
134 setCurrentThreadName (threadName_
);
136 if (startSuspensionEvent_
.wait (10000))
138 jassert (getCurrentThreadId() == threadId_
);
140 if (affinityMask_
!= 0)
141 setCurrentThreadAffinityMask (affinityMask_
);
146 JUCE_CATCH_ALL_ASSERT
148 RunningThreadsList::getInstance().remove (this);
152 // used to wrap the incoming call from the platform-specific code
153 void JUCE_API
juce_threadEntryPoint (void* userData
)
155 static_cast <Thread
*> (userData
)->threadEntryPoint();
159 //==============================================================================
160 Thread::Thread (const String
& threadName
)
161 : threadName_ (threadName
),
162 threadHandle_ (nullptr),
166 threadShouldExit_ (false)
172 /* If your thread class's destructor has been called without first stopping the thread, that
173 means that this partially destructed object is still performing some work - and that's
174 probably a Bad Thing!
176 To avoid this type of nastiness, always make sure you call stopThread() before or during
177 your subclass's destructor.
179 jassert (! isThreadRunning());
184 //==============================================================================
185 void Thread::startThread()
187 const ScopedLock
sl (startStopLock
);
189 threadShouldExit_
= false;
191 if (threadHandle_
== nullptr)
194 setThreadPriority (threadHandle_
, threadPriority_
);
195 startSuspensionEvent_
.signal();
199 void Thread::startThread (const int priority
)
201 const ScopedLock
sl (startStopLock
);
203 if (threadHandle_
== nullptr)
205 threadPriority_
= priority
;
210 setPriority (priority
);
214 bool Thread::isThreadRunning() const
216 return threadHandle_
!= nullptr;
219 //==============================================================================
220 void Thread::signalThreadShouldExit()
222 threadShouldExit_
= true;
225 bool Thread::waitForThreadToExit (const int timeOutMilliseconds
) const
227 // Doh! So how exactly do you expect this thread to wait for itself to stop??
228 jassert (getThreadId() != getCurrentThreadId());
230 const int sleepMsPerIteration
= 5;
231 int count
= timeOutMilliseconds
/ sleepMsPerIteration
;
233 while (isThreadRunning())
235 if (timeOutMilliseconds
> 0 && --count
< 0)
238 sleep (sleepMsPerIteration
);
244 void Thread::stopThread (const int timeOutMilliseconds
)
246 // agh! You can't stop the thread that's calling this method! How on earth
248 jassert (getCurrentThreadId() != getThreadId());
250 const ScopedLock
sl (startStopLock
);
252 if (isThreadRunning())
254 signalThreadShouldExit();
257 if (timeOutMilliseconds
!= 0)
258 waitForThreadToExit (timeOutMilliseconds
);
260 if (isThreadRunning())
262 // very bad karma if this point is reached, as there are bound to be
263 // locks and events left in silly states when a thread is killed by force..
265 Logger::writeToLog ("!! killing thread by force !!");
269 RunningThreadsList::getInstance().remove (this);
270 threadHandle_
= nullptr;
276 //==============================================================================
277 bool Thread::setPriority (const int priority
)
279 const ScopedLock
sl (startStopLock
);
281 if (setThreadPriority (threadHandle_
, priority
))
283 threadPriority_
= priority
;
290 bool Thread::setCurrentThreadPriority (const int priority
)
292 return setThreadPriority (0, priority
);
295 void Thread::setAffinityMask (const uint32 affinityMask
)
297 affinityMask_
= affinityMask
;
300 //==============================================================================
301 bool Thread::wait (const int timeOutMilliseconds
) const
303 return defaultEvent_
.wait (timeOutMilliseconds
);
306 void Thread::notify() const
308 defaultEvent_
.signal();
311 //==============================================================================
312 int Thread::getNumRunningThreads()
314 return RunningThreadsList::getInstance().size();
317 Thread
* Thread::getCurrentThread()
319 return RunningThreadsList::getInstance().getThreadWithID (getCurrentThreadId());
322 void Thread::stopAllThreads (const int timeOutMilliseconds
)
324 RunningThreadsList::getInstance().stopAll (timeOutMilliseconds
);
327 //==============================================================================
328 void SpinLock::enter() const noexcept
332 for (int i
= 20; --i
>= 0;)