mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-17 00:44:19 +00:00
Changed the return type of TimeSliceThreadClient::useTimeSlice().
This commit is contained in:
parent
f01340e4aa
commit
7bfa419f17
12 changed files with 229 additions and 175 deletions
|
|
@ -176,7 +176,7 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if ! JUCE_VC7_OR_EARLIER
|
||||
#if ! JUCE_VC7_OR_EARLIER && ! defined (__INTEL_COMPILER)
|
||||
#define JUCE_USE_INTRINSICS 1
|
||||
#endif
|
||||
#else
|
||||
|
|
@ -17363,9 +17363,7 @@ BEGIN_JUCE_NAMESPACE
|
|||
|
||||
TimeSliceThread::TimeSliceThread (const String& threadName)
|
||||
: Thread (threadName),
|
||||
index (0),
|
||||
clientBeingCalled (0),
|
||||
clientsChanged (false)
|
||||
clientBeingCalled (0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -17374,18 +17372,20 @@ TimeSliceThread::~TimeSliceThread()
|
|||
stopThread (2000);
|
||||
}
|
||||
|
||||
void TimeSliceThread::addTimeSliceClient (TimeSliceClient* const client)
|
||||
void TimeSliceThread::addTimeSliceClient (TimeSliceClient* const client, int millisecondsBeforeStarting)
|
||||
{
|
||||
const ScopedLock sl (listLock);
|
||||
clients.addIfNotAlreadyThere (client);
|
||||
clientsChanged = true;
|
||||
notify();
|
||||
if (client != 0)
|
||||
{
|
||||
const ScopedLock sl (listLock);
|
||||
client->nextCallTime = Time::getCurrentTime() + RelativeTime::milliseconds (millisecondsBeforeStarting);
|
||||
clients.addIfNotAlreadyThere (client);
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
void TimeSliceThread::removeTimeSliceClient (TimeSliceClient* const client)
|
||||
{
|
||||
const ScopedLock sl1 (listLock);
|
||||
clientsChanged = true;
|
||||
|
||||
// if there's a chance we're in the middle of calling this client, we need to
|
||||
// also lock the outer lock..
|
||||
|
|
@ -17415,52 +17415,76 @@ TimeSliceClient* TimeSliceThread::getClient (const int i) const
|
|||
return clients [i];
|
||||
}
|
||||
|
||||
TimeSliceClient* TimeSliceThread::getNextClient (int index) const
|
||||
{
|
||||
Time soonest;
|
||||
TimeSliceClient* client = 0;
|
||||
|
||||
for (int i = clients.size(); --i >= 0;)
|
||||
{
|
||||
TimeSliceClient* const c = clients.getUnchecked ((i + index) % clients.size());
|
||||
|
||||
if (client == 0 || c->nextCallTime < soonest)
|
||||
{
|
||||
client = c;
|
||||
soonest = c->nextCallTime;
|
||||
}
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
void TimeSliceThread::run()
|
||||
{
|
||||
int numCallsSinceBusy = 0;
|
||||
int index = 0;
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
int timeToWait = 500;
|
||||
|
||||
{
|
||||
const ScopedLock sl (callbackLock);
|
||||
Time nextClientTime;
|
||||
|
||||
{
|
||||
const ScopedLock sl2 (listLock);
|
||||
|
||||
if (clients.size() > 0)
|
||||
{
|
||||
index = (index + 1) % clients.size();
|
||||
index = clients.size() > 0 ? ((index + 1) % clients.size()) : 0;
|
||||
|
||||
clientBeingCalled = clients [index];
|
||||
}
|
||||
else
|
||||
{
|
||||
index = 0;
|
||||
clientBeingCalled = 0;
|
||||
}
|
||||
|
||||
if (clientsChanged)
|
||||
{
|
||||
clientsChanged = false;
|
||||
numCallsSinceBusy = 0;
|
||||
}
|
||||
TimeSliceClient* const firstClient = getNextClient (index);
|
||||
if (firstClient != 0)
|
||||
nextClientTime = firstClient->nextCallTime;
|
||||
}
|
||||
|
||||
if (clientBeingCalled != 0)
|
||||
{
|
||||
if (clientBeingCalled->useTimeSlice())
|
||||
numCallsSinceBusy = 0;
|
||||
else
|
||||
++numCallsSinceBusy;
|
||||
const Time now (Time::getCurrentTime());
|
||||
|
||||
if (numCallsSinceBusy >= clients.size())
|
||||
timeToWait = 500;
|
||||
else if (index == 0)
|
||||
timeToWait = 1; // throw in an occasional pause, to stop everything locking up
|
||||
else
|
||||
timeToWait = 0;
|
||||
if (nextClientTime > now)
|
||||
{
|
||||
timeToWait = (int) jmin ((int64) 500, (nextClientTime - now).inMilliseconds());
|
||||
}
|
||||
else
|
||||
{
|
||||
timeToWait = index == 0 ? 1 : 0;
|
||||
|
||||
const ScopedLock sl (callbackLock);
|
||||
|
||||
{
|
||||
const ScopedLock sl2 (listLock);
|
||||
clientBeingCalled = getNextClient (index);
|
||||
}
|
||||
|
||||
if (clientBeingCalled != 0)
|
||||
{
|
||||
const int msUntilNextCall = clientBeingCalled->useTimeSlice();
|
||||
|
||||
const ScopedLock sl2 (listLock);
|
||||
|
||||
if (msUntilNextCall >= 0)
|
||||
clientBeingCalled->nextCallTime += RelativeTime::milliseconds (msUntilNextCall);
|
||||
else
|
||||
clients.removeValue (clientBeingCalled);
|
||||
|
||||
clientBeingCalled = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -21509,7 +21533,7 @@ public:
|
|||
isRunning = false;
|
||||
timeSliceThread.removeTimeSliceClient (this);
|
||||
|
||||
while (useTimeSlice())
|
||||
while (useTimeSlice() == 0)
|
||||
{}
|
||||
}
|
||||
|
||||
|
|
@ -21537,7 +21561,7 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool useTimeSlice()
|
||||
int useTimeSlice()
|
||||
{
|
||||
const int numToDo = getTotalSize() / 4;
|
||||
|
||||
|
|
@ -21545,7 +21569,7 @@ public:
|
|||
prepareToRead (numToDo, start1, size1, start2, size2);
|
||||
|
||||
if (size1 <= 0)
|
||||
return false;
|
||||
return 10;
|
||||
|
||||
writer->writeFromAudioSampleBuffer (buffer, start1, size1);
|
||||
|
||||
|
|
@ -21566,7 +21590,7 @@ public:
|
|||
}
|
||||
|
||||
finishedRead (size1 + size2);
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setThumbnail (AudioThumbnail* thumb)
|
||||
|
|
@ -21913,8 +21937,7 @@ struct AudioThumbnail::MinMaxValue
|
|||
}
|
||||
};
|
||||
|
||||
class AudioThumbnail::LevelDataSource : public TimeSliceClient,
|
||||
public Timer
|
||||
class AudioThumbnail::LevelDataSource : public TimeSliceClient
|
||||
{
|
||||
public:
|
||||
LevelDataSource (AudioThumbnail& owner_, AudioFormatReader* newReader, int64 hash)
|
||||
|
|
@ -21934,7 +21957,7 @@ public:
|
|||
owner.cache.removeTimeSliceClient (this);
|
||||
}
|
||||
|
||||
enum { timeBeforeDeletingReader = 2000 };
|
||||
enum { timeBeforeDeletingReader = 1000 };
|
||||
|
||||
void initialise (int64 numSamplesFinished_)
|
||||
{
|
||||
|
|
@ -21950,9 +21973,9 @@ public:
|
|||
numChannels = reader->numChannels;
|
||||
sampleRate = reader->sampleRate;
|
||||
|
||||
if (lengthInSamples <= 0)
|
||||
if (lengthInSamples <= 0 || isFullyLoaded())
|
||||
reader = 0;
|
||||
else if (! isFullyLoaded())
|
||||
else
|
||||
owner.cache.addTimeSliceClient (this);
|
||||
}
|
||||
}
|
||||
|
|
@ -21960,7 +21983,14 @@ public:
|
|||
void getLevels (int64 startSample, int numSamples, Array<float>& levels)
|
||||
{
|
||||
const ScopedLock sl (readerLock);
|
||||
createReader();
|
||||
|
||||
if (reader == 0)
|
||||
{
|
||||
createReader();
|
||||
|
||||
if (reader != 0)
|
||||
owner.cache.addTimeSliceClient (this);
|
||||
}
|
||||
|
||||
if (reader != 0)
|
||||
{
|
||||
|
|
@ -21978,19 +22008,16 @@ public:
|
|||
reader = 0;
|
||||
}
|
||||
|
||||
bool useTimeSlice()
|
||||
int useTimeSlice()
|
||||
{
|
||||
if (isFullyLoaded())
|
||||
{
|
||||
if (reader != 0 && source != 0)
|
||||
startTimer (timeBeforeDeletingReader);
|
||||
releaseResources();
|
||||
|
||||
owner.cache.removeTimeSliceClient (this);
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
stopTimer();
|
||||
|
||||
bool justFinished = false;
|
||||
|
||||
{
|
||||
|
|
@ -22001,7 +22028,7 @@ public:
|
|||
if (reader != 0)
|
||||
{
|
||||
if (! readNextBlock())
|
||||
return true;
|
||||
return 0;
|
||||
|
||||
justFinished = true;
|
||||
}
|
||||
|
|
@ -22010,13 +22037,7 @@ public:
|
|||
if (justFinished)
|
||||
owner.cache.storeThumb (owner, hashCode);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void timerCallback()
|
||||
{
|
||||
stopTimer();
|
||||
releaseResources();
|
||||
return timeBeforeDeletingReader;
|
||||
}
|
||||
|
||||
bool isFullyLoaded() const throw()
|
||||
|
|
@ -57840,7 +57861,7 @@ void DirectoryContentsList::changed()
|
|||
sendChangeMessage();
|
||||
}
|
||||
|
||||
bool DirectoryContentsList::useTimeSlice()
|
||||
int DirectoryContentsList::useTimeSlice()
|
||||
{
|
||||
const uint32 startTime = Time::getApproximateMillisecondCounter();
|
||||
bool hasChanged = false;
|
||||
|
|
@ -57852,7 +57873,7 @@ bool DirectoryContentsList::useTimeSlice()
|
|||
if (hasChanged)
|
||||
changed();
|
||||
|
||||
return false;
|
||||
return 500;
|
||||
}
|
||||
|
||||
if (shouldStop || (Time::getApproximateMillisecondCounter() > startTime + 150))
|
||||
|
|
@ -57862,7 +57883,7 @@ bool DirectoryContentsList::useTimeSlice()
|
|||
if (hasChanged)
|
||||
changed();
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DirectoryContentsList::checkNextFile (bool& hasChanged)
|
||||
|
|
@ -58957,10 +58978,10 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
bool useTimeSlice()
|
||||
int useTimeSlice()
|
||||
{
|
||||
updateIcon (false);
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void handleAsyncUpdate()
|
||||
|
|
@ -59655,11 +59676,10 @@ public:
|
|||
owner.sendSelectionChangeMessage();
|
||||
}
|
||||
|
||||
bool useTimeSlice()
|
||||
int useTimeSlice()
|
||||
{
|
||||
updateIcon (false);
|
||||
thread.removeTimeSliceClient (this);
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void handleAsyncUpdate()
|
||||
|
|
@ -61201,7 +61221,7 @@ public:
|
|||
component->setVisible (! useProxyComponent);
|
||||
}
|
||||
|
||||
bool useTimeslice (const int elapsed)
|
||||
int useTimeslice (const int elapsed)
|
||||
{
|
||||
Component* const c = proxy != 0 ? static_cast <Component*> (proxy)
|
||||
: static_cast <Component*> (component);
|
||||
|
|
@ -61249,13 +61269,13 @@ public:
|
|||
}
|
||||
|
||||
if (stillBusy)
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
moveToFinalDestination();
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void moveToFinalDestination()
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ namespace JuceDummyNamespace {}
|
|||
*/
|
||||
#define JUCE_MAJOR_VERSION 1
|
||||
#define JUCE_MINOR_VERSION 53
|
||||
#define JUCE_BUILDNUMBER 15
|
||||
#define JUCE_BUILDNUMBER 16
|
||||
|
||||
/** Current Juce version number.
|
||||
|
||||
|
|
@ -223,7 +223,7 @@ namespace JuceDummyNamespace {}
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if ! JUCE_VC7_OR_EARLIER
|
||||
#if ! JUCE_VC7_OR_EARLIER && ! defined (__INTEL_COMPILER)
|
||||
#define JUCE_USE_INTRINSICS 1
|
||||
#endif
|
||||
#else
|
||||
|
|
@ -19825,6 +19825,8 @@ private:
|
|||
#ifndef __JUCE_TIMESLICETHREAD_JUCEHEADER__
|
||||
#define __JUCE_TIMESLICETHREAD_JUCEHEADER__
|
||||
|
||||
class TimeSliceThread;
|
||||
|
||||
/**
|
||||
Used by the TimeSliceThread class.
|
||||
|
||||
|
|
@ -19850,13 +19852,18 @@ public:
|
|||
The implementation of this method should use its time-slice to do something that's
|
||||
quick - never block for longer than absolutely necessary.
|
||||
|
||||
@returns Your method should return true if it needs more time, or false if it's
|
||||
not too busy and doesn't need calling back urgently. If all the thread's
|
||||
clients indicate that they're not busy, then it'll save CPU by sleeping for
|
||||
up to half a second in between callbacks. You can force the TimeSliceThread
|
||||
to wake up and poll again immediately by calling its notify() method.
|
||||
@returns Your method should return the number of milliseconds which it would like to wait before being called
|
||||
again. Returning 0 will make the thread call again as soon as possible (after possibly servicing
|
||||
other busy clients). If you return a value below zero, your client will be removed from the list of clients,
|
||||
and won't be called again. The value you specify isn't a guaranteee, and is only used as a hint by the
|
||||
thread - the actual time before the next callback may be more or less than specified.
|
||||
You can force the TimeSliceThread to wake up and poll again immediately by calling its notify() method.
|
||||
*/
|
||||
virtual bool useTimeSlice() = 0;
|
||||
virtual int useTimeSlice() = 0;
|
||||
|
||||
private:
|
||||
friend class TimeSliceThread;
|
||||
Time nextCallTime;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -19888,10 +19895,10 @@ public:
|
|||
|
||||
/** Adds a client to the list.
|
||||
|
||||
The client's callbacks will start immediately (possibly before the method
|
||||
has returned).
|
||||
The client's callbacks will start after the number of milliseconds specified
|
||||
by millisecondsBeforeStarting (and this may happen before this method has returned).
|
||||
*/
|
||||
void addTimeSliceClient (TimeSliceClient* client);
|
||||
void addTimeSliceClient (TimeSliceClient* client, int millisecondsBeforeStarting = 0);
|
||||
|
||||
/** Removes a client from the list.
|
||||
|
||||
|
|
@ -19912,9 +19919,9 @@ public:
|
|||
private:
|
||||
CriticalSection callbackLock, listLock;
|
||||
Array <TimeSliceClient*> clients;
|
||||
int index;
|
||||
TimeSliceClient* clientBeingCalled;
|
||||
bool clientsChanged;
|
||||
|
||||
TimeSliceClient* getNextClient (int index) const;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimeSliceThread);
|
||||
};
|
||||
|
|
@ -51277,7 +51284,7 @@ public:
|
|||
const FileFilter* getFilter() const { return fileFilter; }
|
||||
|
||||
/** @internal */
|
||||
bool useTimeSlice();
|
||||
int useTimeSlice();
|
||||
/** @internal */
|
||||
TimeSliceThread& getTimeSliceThread() { return thread; }
|
||||
/** @internal */
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ public:
|
|||
isRunning = false;
|
||||
timeSliceThread.removeTimeSliceClient (this);
|
||||
|
||||
while (useTimeSlice())
|
||||
while (useTimeSlice() == 0)
|
||||
{}
|
||||
}
|
||||
|
||||
|
|
@ -229,7 +229,7 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool useTimeSlice()
|
||||
int useTimeSlice()
|
||||
{
|
||||
const int numToDo = getTotalSize() / 4;
|
||||
|
||||
|
|
@ -237,7 +237,7 @@ public:
|
|||
prepareToRead (numToDo, start1, size1, start2, size2);
|
||||
|
||||
if (size1 <= 0)
|
||||
return false;
|
||||
return 10;
|
||||
|
||||
writer->writeFromAudioSampleBuffer (buffer, start1, size1);
|
||||
|
||||
|
|
@ -258,7 +258,7 @@ public:
|
|||
}
|
||||
|
||||
finishedRead (size1 + size2);
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setThumbnail (AudioThumbnail* thumb)
|
||||
|
|
|
|||
|
|
@ -82,8 +82,7 @@ struct AudioThumbnail::MinMaxValue
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
class AudioThumbnail::LevelDataSource : public TimeSliceClient,
|
||||
public Timer
|
||||
class AudioThumbnail::LevelDataSource : public TimeSliceClient
|
||||
{
|
||||
public:
|
||||
LevelDataSource (AudioThumbnail& owner_, AudioFormatReader* newReader, int64 hash)
|
||||
|
|
@ -103,7 +102,7 @@ public:
|
|||
owner.cache.removeTimeSliceClient (this);
|
||||
}
|
||||
|
||||
enum { timeBeforeDeletingReader = 2000 };
|
||||
enum { timeBeforeDeletingReader = 1000 };
|
||||
|
||||
void initialise (int64 numSamplesFinished_)
|
||||
{
|
||||
|
|
@ -119,9 +118,9 @@ public:
|
|||
numChannels = reader->numChannels;
|
||||
sampleRate = reader->sampleRate;
|
||||
|
||||
if (lengthInSamples <= 0)
|
||||
if (lengthInSamples <= 0 || isFullyLoaded())
|
||||
reader = 0;
|
||||
else if (! isFullyLoaded())
|
||||
else
|
||||
owner.cache.addTimeSliceClient (this);
|
||||
}
|
||||
}
|
||||
|
|
@ -129,7 +128,14 @@ public:
|
|||
void getLevels (int64 startSample, int numSamples, Array<float>& levels)
|
||||
{
|
||||
const ScopedLock sl (readerLock);
|
||||
createReader();
|
||||
|
||||
if (reader == 0)
|
||||
{
|
||||
createReader();
|
||||
|
||||
if (reader != 0)
|
||||
owner.cache.addTimeSliceClient (this);
|
||||
}
|
||||
|
||||
if (reader != 0)
|
||||
{
|
||||
|
|
@ -147,19 +153,16 @@ public:
|
|||
reader = 0;
|
||||
}
|
||||
|
||||
bool useTimeSlice()
|
||||
int useTimeSlice()
|
||||
{
|
||||
if (isFullyLoaded())
|
||||
{
|
||||
if (reader != 0 && source != 0)
|
||||
startTimer (timeBeforeDeletingReader);
|
||||
releaseResources();
|
||||
|
||||
owner.cache.removeTimeSliceClient (this);
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
stopTimer();
|
||||
|
||||
bool justFinished = false;
|
||||
|
||||
{
|
||||
|
|
@ -170,7 +173,7 @@ public:
|
|||
if (reader != 0)
|
||||
{
|
||||
if (! readNextBlock())
|
||||
return true;
|
||||
return 0;
|
||||
|
||||
justFinished = true;
|
||||
}
|
||||
|
|
@ -179,13 +182,7 @@ public:
|
|||
if (justFinished)
|
||||
owner.cache.storeThumb (owner, hashCode);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void timerCallback()
|
||||
{
|
||||
stopTimer();
|
||||
releaseResources();
|
||||
return timeBeforeDeletingReader;
|
||||
}
|
||||
|
||||
bool isFullyLoaded() const throw()
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
*/
|
||||
#define JUCE_MAJOR_VERSION 1
|
||||
#define JUCE_MINOR_VERSION 53
|
||||
#define JUCE_BUILDNUMBER 15
|
||||
#define JUCE_BUILDNUMBER 16
|
||||
|
||||
/** Current Juce version number.
|
||||
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if ! JUCE_VC7_OR_EARLIER
|
||||
#if ! JUCE_VC7_OR_EARLIER && ! defined (__INTEL_COMPILER)
|
||||
#define JUCE_USE_INTRINSICS 1
|
||||
#endif
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ void DirectoryContentsList::changed()
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
bool DirectoryContentsList::useTimeSlice()
|
||||
int DirectoryContentsList::useTimeSlice()
|
||||
{
|
||||
const uint32 startTime = Time::getApproximateMillisecondCounter();
|
||||
bool hasChanged = false;
|
||||
|
|
@ -177,7 +177,7 @@ bool DirectoryContentsList::useTimeSlice()
|
|||
if (hasChanged)
|
||||
changed();
|
||||
|
||||
return false;
|
||||
return 500;
|
||||
}
|
||||
|
||||
if (shouldStop || (Time::getApproximateMillisecondCounter() > startTime + 150))
|
||||
|
|
@ -187,7 +187,7 @@ bool DirectoryContentsList::useTimeSlice()
|
|||
if (hasChanged)
|
||||
changed();
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DirectoryContentsList::checkNextFile (bool& hasChanged)
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ public:
|
|||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
bool useTimeSlice();
|
||||
int useTimeSlice();
|
||||
/** @internal */
|
||||
TimeSliceThread& getTimeSliceThread() { return thread; }
|
||||
/** @internal */
|
||||
|
|
|
|||
|
|
@ -165,10 +165,10 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
bool useTimeSlice()
|
||||
int useTimeSlice()
|
||||
{
|
||||
updateIcon (false);
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void handleAsyncUpdate()
|
||||
|
|
|
|||
|
|
@ -173,11 +173,10 @@ public:
|
|||
owner.sendSelectionChangeMessage();
|
||||
}
|
||||
|
||||
bool useTimeSlice()
|
||||
int useTimeSlice()
|
||||
{
|
||||
updateIcon (false);
|
||||
thread.removeTimeSliceClient (this);
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void handleAsyncUpdate()
|
||||
|
|
|
|||
|
|
@ -34,9 +34,7 @@ BEGIN_JUCE_NAMESPACE
|
|||
//==============================================================================
|
||||
TimeSliceThread::TimeSliceThread (const String& threadName)
|
||||
: Thread (threadName),
|
||||
index (0),
|
||||
clientBeingCalled (0),
|
||||
clientsChanged (false)
|
||||
clientBeingCalled (0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -46,18 +44,20 @@ TimeSliceThread::~TimeSliceThread()
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void TimeSliceThread::addTimeSliceClient (TimeSliceClient* const client)
|
||||
void TimeSliceThread::addTimeSliceClient (TimeSliceClient* const client, int millisecondsBeforeStarting)
|
||||
{
|
||||
const ScopedLock sl (listLock);
|
||||
clients.addIfNotAlreadyThere (client);
|
||||
clientsChanged = true;
|
||||
notify();
|
||||
if (client != 0)
|
||||
{
|
||||
const ScopedLock sl (listLock);
|
||||
client->nextCallTime = Time::getCurrentTime() + RelativeTime::milliseconds (millisecondsBeforeStarting);
|
||||
clients.addIfNotAlreadyThere (client);
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
void TimeSliceThread::removeTimeSliceClient (TimeSliceClient* const client)
|
||||
{
|
||||
const ScopedLock sl1 (listLock);
|
||||
clientsChanged = true;
|
||||
|
||||
// if there's a chance we're in the middle of calling this client, we need to
|
||||
// also lock the outer lock..
|
||||
|
|
@ -88,52 +88,76 @@ TimeSliceClient* TimeSliceThread::getClient (const int i) const
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
TimeSliceClient* TimeSliceThread::getNextClient (int index) const
|
||||
{
|
||||
Time soonest;
|
||||
TimeSliceClient* client = 0;
|
||||
|
||||
for (int i = clients.size(); --i >= 0;)
|
||||
{
|
||||
TimeSliceClient* const c = clients.getUnchecked ((i + index) % clients.size());
|
||||
|
||||
if (client == 0 || c->nextCallTime < soonest)
|
||||
{
|
||||
client = c;
|
||||
soonest = c->nextCallTime;
|
||||
}
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
void TimeSliceThread::run()
|
||||
{
|
||||
int numCallsSinceBusy = 0;
|
||||
int index = 0;
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
int timeToWait = 500;
|
||||
|
||||
{
|
||||
const ScopedLock sl (callbackLock);
|
||||
Time nextClientTime;
|
||||
|
||||
{
|
||||
const ScopedLock sl2 (listLock);
|
||||
|
||||
if (clients.size() > 0)
|
||||
{
|
||||
index = (index + 1) % clients.size();
|
||||
index = clients.size() > 0 ? ((index + 1) % clients.size()) : 0;
|
||||
|
||||
clientBeingCalled = clients [index];
|
||||
}
|
||||
else
|
||||
{
|
||||
index = 0;
|
||||
clientBeingCalled = 0;
|
||||
}
|
||||
|
||||
if (clientsChanged)
|
||||
{
|
||||
clientsChanged = false;
|
||||
numCallsSinceBusy = 0;
|
||||
}
|
||||
TimeSliceClient* const firstClient = getNextClient (index);
|
||||
if (firstClient != 0)
|
||||
nextClientTime = firstClient->nextCallTime;
|
||||
}
|
||||
|
||||
if (clientBeingCalled != 0)
|
||||
{
|
||||
if (clientBeingCalled->useTimeSlice())
|
||||
numCallsSinceBusy = 0;
|
||||
else
|
||||
++numCallsSinceBusy;
|
||||
const Time now (Time::getCurrentTime());
|
||||
|
||||
if (numCallsSinceBusy >= clients.size())
|
||||
timeToWait = 500;
|
||||
else if (index == 0)
|
||||
timeToWait = 1; // throw in an occasional pause, to stop everything locking up
|
||||
else
|
||||
timeToWait = 0;
|
||||
if (nextClientTime > now)
|
||||
{
|
||||
timeToWait = (int) jmin ((int64) 500, (nextClientTime - now).inMilliseconds());
|
||||
}
|
||||
else
|
||||
{
|
||||
timeToWait = index == 0 ? 1 : 0;
|
||||
|
||||
const ScopedLock sl (callbackLock);
|
||||
|
||||
{
|
||||
const ScopedLock sl2 (listLock);
|
||||
clientBeingCalled = getNextClient (index);
|
||||
}
|
||||
|
||||
if (clientBeingCalled != 0)
|
||||
{
|
||||
const int msUntilNextCall = clientBeingCalled->useTimeSlice();
|
||||
|
||||
const ScopedLock sl2 (listLock);
|
||||
|
||||
if (msUntilNextCall >= 0)
|
||||
clientBeingCalled->nextCallTime += RelativeTime::milliseconds (msUntilNextCall);
|
||||
else
|
||||
clients.removeValue (clientBeingCalled);
|
||||
|
||||
clientBeingCalled = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@
|
|||
|
||||
#include "juce_Thread.h"
|
||||
#include "../containers/juce_Array.h"
|
||||
|
||||
#include "../core/juce_Time.h"
|
||||
class TimeSliceThread;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
|
|
@ -56,13 +57,19 @@ public:
|
|||
The implementation of this method should use its time-slice to do something that's
|
||||
quick - never block for longer than absolutely necessary.
|
||||
|
||||
@returns Your method should return true if it needs more time, or false if it's
|
||||
not too busy and doesn't need calling back urgently. If all the thread's
|
||||
clients indicate that they're not busy, then it'll save CPU by sleeping for
|
||||
up to half a second in between callbacks. You can force the TimeSliceThread
|
||||
to wake up and poll again immediately by calling its notify() method.
|
||||
@returns Your method should return the number of milliseconds which it would like to wait before being called
|
||||
again. Returning 0 will make the thread call again as soon as possible (after possibly servicing
|
||||
other busy clients). If you return a value below zero, your client will be removed from the list of clients,
|
||||
and won't be called again. The value you specify isn't a guaranteee, and is only used as a hint by the
|
||||
thread - the actual time before the next callback may be more or less than specified.
|
||||
You can force the TimeSliceThread to wake up and poll again immediately by calling its notify() method.
|
||||
*/
|
||||
virtual bool useTimeSlice() = 0;
|
||||
virtual int useTimeSlice() = 0;
|
||||
|
||||
|
||||
private:
|
||||
friend class TimeSliceThread;
|
||||
Time nextCallTime;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -97,10 +104,10 @@ public:
|
|||
//==============================================================================
|
||||
/** Adds a client to the list.
|
||||
|
||||
The client's callbacks will start immediately (possibly before the method
|
||||
has returned).
|
||||
The client's callbacks will start after the number of milliseconds specified
|
||||
by millisecondsBeforeStarting (and this may happen before this method has returned).
|
||||
*/
|
||||
void addTimeSliceClient (TimeSliceClient* client);
|
||||
void addTimeSliceClient (TimeSliceClient* client, int millisecondsBeforeStarting = 0);
|
||||
|
||||
/** Removes a client from the list.
|
||||
|
||||
|
|
@ -123,9 +130,9 @@ public:
|
|||
private:
|
||||
CriticalSection callbackLock, listLock;
|
||||
Array <TimeSliceClient*> clients;
|
||||
int index;
|
||||
TimeSliceClient* clientBeingCalled;
|
||||
bool clientsChanged;
|
||||
|
||||
TimeSliceClient* getNextClient (int index) const;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimeSliceThread);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue