1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-11 23:54:18 +00:00
JUCE/src/threads/juce_Thread.cpp

285 lines
7.5 KiB
C++

/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-9 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/
#include "../core/juce_StandardHeader.h"
BEGIN_JUCE_NAMESPACE
#include "juce_Thread.h"
#include "juce_ScopedLock.h"
#include "../core/juce_Time.h"
#include "../containers/juce_VoidArray.h"
// these functions are implemented in the platform-specific code.
void* juce_createThread (void* userData);
void juce_killThread (void* handle);
bool juce_setThreadPriority (void* handle, int priority);
void juce_setCurrentThreadName (const String& name);
#if JUCE_WIN32
void juce_CloseThreadHandle (void* handle);
#endif
//==============================================================================
static VoidArray runningThreads;
static CriticalSection runningThreadsLock;
//==============================================================================
void Thread::threadEntryPoint (Thread* const thread)
{
{
const ScopedLock sl (runningThreadsLock);
runningThreads.add (thread);
}
JUCE_TRY
{
thread->threadId_ = Thread::getCurrentThreadId();
if (thread->threadName_.isNotEmpty())
juce_setCurrentThreadName (thread->threadName_);
if (thread->startSuspensionEvent_.wait (10000))
{
if (thread->affinityMask_ != 0)
setCurrentThreadAffinityMask (thread->affinityMask_);
thread->run();
}
}
JUCE_CATCH_ALL_ASSERT
{
const ScopedLock sl (runningThreadsLock);
jassert (runningThreads.contains (thread));
runningThreads.removeValue (thread);
}
#if JUCE_WIN32
juce_CloseThreadHandle (thread->threadHandle_);
#endif
thread->threadHandle_ = 0;
thread->threadId_ = 0;
}
// used to wrap the incoming call from the platform-specific code
void JUCE_API juce_threadEntryPoint (void* userData)
{
Thread::threadEntryPoint ((Thread*) userData);
}
//==============================================================================
Thread::Thread (const String& threadName)
: threadName_ (threadName),
threadHandle_ (0),
threadPriority_ (5),
threadId_ (0),
affinityMask_ (0),
threadShouldExit_ (false)
{
}
Thread::~Thread()
{
stopThread (100);
}
//==============================================================================
void Thread::startThread()
{
const ScopedLock sl (startStopLock);
threadShouldExit_ = false;
if (threadHandle_ == 0)
{
threadHandle_ = juce_createThread ((void*) this);
juce_setThreadPriority (threadHandle_, threadPriority_);
startSuspensionEvent_.signal();
}
}
void Thread::startThread (const int priority)
{
const ScopedLock sl (startStopLock);
if (threadHandle_ == 0)
{
threadPriority_ = priority;
startThread();
}
else
{
setPriority (priority);
}
}
bool Thread::isThreadRunning() const
{
return threadHandle_ != 0;
}
//==============================================================================
void Thread::signalThreadShouldExit()
{
threadShouldExit_ = true;
}
bool Thread::waitForThreadToExit (const int timeOutMilliseconds) const
{
// Doh! So how exactly do you expect this thread to wait for itself to stop??
jassert (getThreadId() != getCurrentThreadId());
const int sleepMsPerIteration = 5;
int count = timeOutMilliseconds / sleepMsPerIteration;
while (isThreadRunning())
{
if (timeOutMilliseconds > 0 && --count < 0)
return false;
sleep (sleepMsPerIteration);
}
return true;
}
void Thread::stopThread (const int timeOutMilliseconds)
{
// agh! You can't stop the thread that's calling this method! How on earth
// would that work??
jassert (getCurrentThreadId() != getThreadId());
const ScopedLock sl (startStopLock);
if (isThreadRunning())
{
signalThreadShouldExit();
notify();
if (timeOutMilliseconds != 0)
waitForThreadToExit (timeOutMilliseconds);
if (isThreadRunning())
{
// very bad karma if this point is reached, as
// there are bound to be locks and events left in
// silly states when a thread is killed by force..
jassertfalse
Logger::writeToLog ("!! killing thread by force !!");
juce_killThread (threadHandle_);
threadHandle_ = 0;
threadId_ = 0;
const ScopedLock sl2 (runningThreadsLock);
runningThreads.removeValue (this);
}
}
}
//==============================================================================
bool Thread::setPriority (const int priority)
{
const ScopedLock sl (startStopLock);
const bool worked = juce_setThreadPriority (threadHandle_, priority);
if (worked)
threadPriority_ = priority;
return worked;
}
bool Thread::setCurrentThreadPriority (const int priority)
{
return juce_setThreadPriority (0, priority);
}
void Thread::setAffinityMask (const uint32 affinityMask)
{
affinityMask_ = affinityMask;
}
//==============================================================================
bool Thread::wait (const int timeOutMilliseconds) const
{
return defaultEvent_.wait (timeOutMilliseconds);
}
void Thread::notify() const
{
defaultEvent_.signal();
}
//==============================================================================
int Thread::getNumRunningThreads()
{
return runningThreads.size();
}
Thread* Thread::getCurrentThread()
{
const ThreadID thisId = getCurrentThreadId();
const ScopedLock sl (runningThreadsLock);
for (int i = runningThreads.size(); --i >= 0;)
{
Thread* const t = (Thread*) runningThreads.getUnchecked(i);
if (t->threadId_ == thisId)
return t;
}
return 0;
}
void Thread::stopAllThreads (const int timeOutMilliseconds)
{
{
const ScopedLock sl (runningThreadsLock);
for (int i = runningThreads.size(); --i >= 0;)
((Thread*) runningThreads.getUnchecked(i))->signalThreadShouldExit();
}
for (;;)
{
runningThreadsLock.enter();
Thread* const t = (Thread*) runningThreads[0];
runningThreadsLock.exit();
if (t == 0)
break;
t->stopThread (timeOutMilliseconds);
}
}
END_JUCE_NAMESPACE