2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-9 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 "../jucedemo_headers.h"
29 //==============================================================================
30 class BouncingBallComp
: public Component
35 x
= Random::getSystemRandom().nextFloat() * 200.0f
;
36 y
= Random::getSystemRandom().nextFloat() * 200.0f
;
43 const float speed
= 5.0f
; // give each ball a fixed speed so we can
44 // see the effects of thread priority on how fast
46 const float angle
= Random::getSystemRandom().nextFloat() * float_Pi
* 2.0f
;
48 dx
= sinf (angle
) * speed
;
49 dy
= cosf (angle
) * speed
;
51 size
= Random::getSystemRandom().nextFloat() * 30.0f
+ 30.0f
;
53 colour
= Colour (Random::getSystemRandom().nextInt())
55 .withBrightness (0.7f
);
62 void paint (Graphics
& g
)
65 g
.fillEllipse (innerX
, innerY
, size
, size
);
67 g
.setColour (Colours::black
);
69 g
.drawText (String::toHexString ((int64
) threadId
), 0, 0, getWidth(), getHeight(), Justification::centred
, false);
72 void parentSizeChanged()
74 parentWidth
= getParentWidth() - size
;
75 parentHeight
= getParentHeight() - size
;
80 threadId
= Thread::getCurrentThreadId(); // this is so the component can print the thread ID inside the ball
97 setBounds (((int) x
) - 2,
109 float x
, y
, size
, dx
, dy
, w
, h
, parentWidth
, parentHeight
;
110 float innerX
, innerY
;
112 Thread::ThreadID threadId
;
114 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BouncingBallComp
);
118 //==============================================================================
119 class DemoThread
: public BouncingBallComp
,
124 : Thread ("Juce Demo Thread")
126 interval
= Random::getSystemRandom().nextInt (50) + 6;
128 // give the threads a random priority, so some will move more
129 // smoothly than others..
130 startThread (Random::getSystemRandom().nextInt (3) + 3);
135 // allow the thread 2 seconds to stop cleanly - should be plenty of time.
141 // this is the code that runs this thread - we'll loop continuously,
142 // updating the co-ordinates of our blob.
144 // threadShouldExit() returns true when the stopThread() method has been
145 // called, so we should check it often, and exit as soon as it gets flagged.
146 while (! threadShouldExit())
148 // sleep a bit so the threads don't all grind the CPU to a halt..
151 // because this is a background thread, we mustn't do any UI work without
152 // first grabbing a MessageManagerLock..
153 const MessageManagerLock
mml (Thread::getCurrentThread());
155 if (! mml
.lockWasGained()) // if something is trying to kill this job, the lock
156 return; // will fail, in which case we'd better return..
158 // now we've got the UI thread locked, we can mess about with the components
166 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DemoThread
);
170 //==============================================================================
171 class DemoThreadPoolJob
: public BouncingBallComp
,
176 : ThreadPoolJob ("Demo Threadpool Job")
186 // this is the code that runs this job. It'll be repeatedly called until we return
187 // jobHasFinished instead of jobNeedsRunningAgain.
192 // because this is a background thread, we mustn't do any UI work without
193 // first grabbing a MessageManagerLock..
194 const MessageManagerLock
mml (this);
196 // before moving the ball, we need to check whether the lock was actually gained, because
197 // if something is trying to stop this job, it will have failed..
198 if (mml
.lockWasGained())
201 return jobNeedsRunningAgain
;
204 void removedFromQueue()
206 // This is called to tell us that our job has been removed from the pool.
207 // In this case there's no need to do anything here.
211 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DemoThreadPoolJob
);
214 //==============================================================================
215 class ThreadingDemo
: public Component
,
217 public ButtonListener
220 //==============================================================================
223 controlButton ("Thread type"),
226 setName ("Multithreading");
230 addAndMakeVisible (&controlButton
);
231 controlButton
.changeWidthToFitText (20);
232 controlButton
.setTopLeftPosition (20, 20);
233 controlButton
.setTriggeredOnMouseDown (true);
234 controlButton
.setAlwaysOnTop (true);
235 controlButton
.addListener (this);
240 pool
.removeAllJobs (true, 2000);
247 pool
.removeAllJobs (true, 4000);
252 while (balls
.size() < 5)
259 void paint (Graphics
& g
)
261 g
.fillAll (Colours::white
);
264 void setUsingPool (bool usePool
)
266 isUsingPool
= usePool
;
274 DemoThreadPoolJob
* newBall
= new DemoThreadPoolJob();
276 addAndMakeVisible (newBall
);
277 newBall
->parentSizeChanged();
279 pool
.addJob (newBall
);
283 DemoThread
* newBall
= new DemoThread();
285 addAndMakeVisible (newBall
);
286 newBall
->parentSizeChanged();
292 if (balls
.size() > 0)
294 int indexToRemove
= Random::getSystemRandom().nextInt (balls
.size());
297 pool
.removeJob (dynamic_cast <DemoThreadPoolJob
*> (balls
[indexToRemove
]), true, 4000);
299 balls
.remove (indexToRemove
);
305 if (Random::getSystemRandom().nextBool())
307 if (balls
.size() <= 10)
312 if (balls
.size() > 3)
317 void buttonClicked (Button
*)
320 m
.addItem (1, "Use one thread per ball", true, ! isUsingPool
);
321 m
.addItem (2, "Use a thread pool", true, isUsingPool
);
323 m
.showMenuAsync (PopupMenu::Options().withTargetComponent (&controlButton
),
324 ModalCallbackFunction::forComponent (menuItemChosenCallback
, this));
327 static void menuItemChosenCallback (int result
, ThreadingDemo
* demoComponent
)
329 if (demoComponent
!= 0)
330 demoComponent
->setUsingPool (result
== 2);
333 // this gets called when a component is added or removed from a parent component.
334 void parentHierarchyChanged()
336 // we'll use this as an opportunity to start and stop the threads, so that
337 // we don't leave them going when the component's not actually visible.
343 TextButton controlButton
;
346 OwnedArray
<Component
> balls
;
351 //==============================================================================
352 Component
* createThreadingDemo()
354 return new ThreadingDemo();