From 283521f1df0501cda3b3efd78bd1fcc28c7b6482 Mon Sep 17 00:00:00 2001 From: Tom Poole Date: Thu, 4 Jul 2019 11:20:39 +0100 Subject: [PATCH] Fixed some issues with the multithreading demo --- .../DemoRunner/Source/UI/MainComponent.cpp | 2 - examples/Utilities/MultithreadingDemo.h | 154 ++++++++---------- 2 files changed, 67 insertions(+), 89 deletions(-) diff --git a/examples/DemoRunner/Source/UI/MainComponent.cpp b/examples/DemoRunner/Source/UI/MainComponent.cpp index 32244a2e00..e7b54fc9a9 100644 --- a/examples/DemoRunner/Source/UI/MainComponent.cpp +++ b/examples/DemoRunner/Source/UI/MainComponent.cpp @@ -245,9 +245,7 @@ MainComponent::MainComponent() { contentComponent.reset (new DemoContentComponent (*this, [this] (bool isHeavyweight) { - #if (JUCE_ANDROID || JUCE_IOS) demosPanel.showOrHide (false); - #endif if (isHeavyweight) { diff --git a/examples/Utilities/MultithreadingDemo.h b/examples/Utilities/MultithreadingDemo.h index d3d8b7db20..1f69967f13 100644 --- a/examples/Utilities/MultithreadingDemo.h +++ b/examples/Utilities/MultithreadingDemo.h @@ -49,11 +49,14 @@ #include "../Assets/DemoUtilities.h" //============================================================================== -class BouncingBallComp : public Component +class BouncingBall : private ComponentListener { public: - BouncingBallComp() + BouncingBall (Component& comp) + : containerComponent (comp) { + containerComponent.addComponentListener (this); + auto speed = 5.0f; // give each ball a fixed speed so we can // see the effects of thread priority on how fast // they actually go. @@ -66,26 +69,35 @@ public: colour = Colour ((juce::uint32) Random::getSystemRandom().nextInt()) .withAlpha (0.5f) .withBrightness (0.7f); + + componentMovedOrResized (containerComponent, true, true); + + x = Random::getSystemRandom().nextFloat() * parentWidth; + y = Random::getSystemRandom().nextFloat() * parentHeight; } - void paint (Graphics& g) override + ~BouncingBall() override + { + containerComponent.removeComponentListener (this); + } + + // This will be called from the message thread + void draw (Graphics& g) { + const ScopedLock lock (drawing); + g.setColour (colour); - g.fillEllipse (innerX, innerY, size, size); + g.fillEllipse (x, y, size, size); g.setColour (Colours::black); g.setFont (10.0f); - g.drawText (String::toHexString ((int64) threadId), getLocalBounds(), Justification::centred, false); - } - - void parentSizeChanged() override - { - parentWidth = getParentWidth() - size; - parentHeight = getParentHeight() - size; + g.drawText (String::toHexString ((int64) threadId), Rectangle (x, y, size, size), Justification::centred, false); } void moveBall() { + const ScopedLock lock (drawing); + threadId = Thread::getCurrentThreadId(); // this is so the component can print the thread ID inside the ball x += dx; @@ -102,39 +114,39 @@ public: if (y > parentHeight) dy = -std::abs (dy); + } - setBounds (((int) x) - 2, - ((int) y) - 2, - ((int) size) + 4, - ((int) size) + 4); - - innerX = x - getX(); - innerY = y - getY(); +private: + void componentMovedOrResized (Component& comp, bool, bool) override + { + const ScopedLock lock (drawing); - repaint(); + parentWidth = comp.getWidth() - size; + parentHeight = comp.getHeight() - size; } -private: - float x = Random::getSystemRandom().nextFloat() * 200.0f, - y = Random::getSystemRandom().nextFloat() * 200.0f, + float x = 0.0f, y = 0.0f, size = Random::getSystemRandom().nextFloat() * 30.0f + 30.0f, - dx = 0.0f, dy = 0.0f, innerX = 0.0f, innerY = 0.0f, + dx = 0.0f, dy = 0.0f, parentWidth = 50.0f, parentHeight = 50.0f; Colour colour; Thread::ThreadID threadId = {}; + CriticalSection drawing; - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BouncingBallComp) -}; + Component& containerComponent; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BouncingBall) +}; //============================================================================== -class DemoThread : public BouncingBallComp, +class DemoThread : public BouncingBall, public Thread { public: - DemoThread() - : Thread ("JUCE Demo Thread") + DemoThread (Component& containerComp) + : BouncingBall (containerComp), + Thread ("JUCE Demo Thread") { // give the threads a random priority, so some will move more // smoothly than others.. @@ -179,12 +191,13 @@ private: //============================================================================== -class DemoThreadPoolJob : public BouncingBallComp, +class DemoThreadPoolJob : public BouncingBall, public ThreadPoolJob { public: - DemoThreadPoolJob() - : ThreadPoolJob ("Demo Threadpool Job") + DemoThreadPoolJob (Component& containerComp) + : BouncingBall (containerComp), + ThreadPoolJob ("Demo Threadpool Job") {} JobStatus runJob() override @@ -220,6 +233,7 @@ class MultithreadingDemo : public Component, private Timer { public: + //============================================================================== MultithreadingDemo() { setOpaque (true); @@ -232,6 +246,10 @@ public: controlButton.onClick = [this] { showMenu(); }; setSize (500, 500); + + resetAllBalls(); + + startTimerHz (60); } ~MultithreadingDemo() override @@ -241,32 +259,23 @@ public: void resetAllBalls() { - stopTimer(); - pool.removeAllJobs (true, 4000); balls.clear(); - if (isShowing()) - { - while (balls.size() < 5) - addABall(); - - startTimer (300); - } + for (int i = 0; i < 5; ++i) + addABall(); } void paint (Graphics& g) override { g.fillAll (getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour::windowBackground)); + + for (auto* ball : balls) + ball->draw (g); } private: - ThreadPool pool { 3 }; - TextButton controlButton { "Thread type" }; - bool isUsingPool = false; - - OwnedArray balls; - + //============================================================================== void setUsingPool (bool usePool) { isUsingPool = usePool; @@ -277,56 +286,20 @@ private: { if (isUsingPool) { - auto* newBall = new DemoThreadPoolJob(); - balls.add (newBall); - addAndMakeVisible (newBall); - newBall->parentSizeChanged(); + auto newBall = std::make_unique (*this); + pool.addJob (newBall.get(), false); + balls.add (newBall.release()); - pool.addJob (newBall, false); } else { - auto* newBall = new DemoThread(); - balls.add (newBall); - addAndMakeVisible (newBall); - newBall->parentSizeChanged(); - } - } - - void removeABall() - { - if (balls.size() > 0) - { - auto indexToRemove = Random::getSystemRandom().nextInt (balls.size()); - - if (isUsingPool) - pool.removeJob (dynamic_cast (balls[indexToRemove]), true, 4000); - - balls.remove (indexToRemove); + balls.add (new DemoThread (*this)); } } - - // this gets called when a component is added or removed from a parent component. - void parentHierarchyChanged() override - { - // we'll use this as an opportunity to start and stop the threads, so that - // we don't leave them going when the component's not actually visible. - resetAllBalls(); - } - void timerCallback() override { - if (Random::getSystemRandom().nextBool()) - { - if (balls.size() <= 10) - addABall(); - } - else - { - if (balls.size() > 3) - removeABall(); - } + repaint(); } void showMenu() @@ -345,5 +318,12 @@ private: demoComponent->setUsingPool (result == 2); } + //============================================================================== + ThreadPool pool { 3 }; + TextButton controlButton { "Thread type" }; + bool isUsingPool = false; + + OwnedArray balls; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultithreadingDemo) };