Browse Source

ChildProcessDemo: Fix crashes when stopping child process

Previously, the child process could be deleted from its own
handleConnectionLost() callback, which would attempt to stop the child
process's thread from that same thread.

Now, the demo will attempt to stop the coordinator thread from the main
thread instead.
v6.1.6
reuk 3 years ago
parent
commit
e5255eb76c
No known key found for this signature in database GPG Key ID: 9ADCD339CFC98A11
1 changed files with 37 additions and 15 deletions
  1. +37
    -15
      examples/Utilities/ChildProcessDemo.h

+ 37
- 15
examples/Utilities/ChildProcessDemo.h View File

@@ -98,7 +98,12 @@ public:
testResultsBox.setFont ({ Font::getDefaultMonospacedFontName(), 12.0f, Font::plain });
logMessage (String ("This demo uses the ChildProcessCoordinator and ChildProcessWorker classes to launch and communicate "
"with a child process, sending messages in the form of serialised ValueTree objects.") + newLine);
"with a child process, sending messages in the form of serialised ValueTree objects.") + newLine
+ String ("In this demo, the child process will automatically quit if it fails to receive a ping message at least every ")
+ String (timeoutSeconds)
+ String (" seconds. To keep the process alive, press the \"")
+ pingButton.getButtonText()
+ String ("\" button periodically.") + newLine);
setSize (500, 500);
}
@@ -136,10 +141,14 @@ public:
{
if (coordinatorProcess.get() == nullptr)
{
coordinatorProcess.reset (new DemoCoordinatorProcess (*this));
coordinatorProcess = std::make_unique<DemoCoordinatorProcess> (*this);
if (coordinatorProcess->launchWorkerProcess (File::getSpecialLocation (File::currentExecutableFile), demoCommandLineUID))
if (coordinatorProcess->launchWorkerProcess (File::getSpecialLocation (File::currentExecutableFile),
demoCommandLineUID,
timeoutMillis))
{
logMessage ("Child process started");
}
}
}
@@ -166,11 +175,14 @@ public:
// This class is used by the main process, acting as the coordinator and receiving messages
// from the worker process.
class DemoCoordinatorProcess : public ChildProcessCoordinator,
private DeletedAtShutdown
private DeletedAtShutdown,
private AsyncUpdater
{
public:
DemoCoordinatorProcess (ChildProcessDemo& d) : demo (d) {}
~DemoCoordinatorProcess() override { cancelPendingUpdate(); }
// This gets called when a message arrives from the worker process..
void handleMessageFromWorker (const MemoryBlock& mb) override
{
@@ -183,6 +195,11 @@ public:
void handleConnectionLost() override
{
demo.logMessage ("Connection lost to child process!");
triggerAsyncUpdate();
}
void handleAsyncUpdate() override
{
demo.killChildProcess();
}
@@ -203,7 +220,11 @@ public:
//==============================================================================
std::unique_ptr<DemoCoordinatorProcess> coordinatorProcess;
static constexpr auto timeoutSeconds = 10;
static constexpr auto timeoutMillis = timeoutSeconds * 1000;
private:
TextButton launchButton { "Launch Child Process" };
TextButton pingButton { "Send Ping" };
TextButton killButton { "Kill Child Process" };
@@ -268,8 +289,8 @@ public:
}
/* If no pings are received from the coordinator process for a number of seconds, then this will get invoked.
Typically you'll want to use this as a signal to kill the process as quickly as possible, as you
don't want to leave it hanging around as a zombie..
Typically, you'll want to use this as a signal to kill the process as quickly as possible, as you
don't want to leave it hanging around as a zombie.
*/
void handleConnectionLost() override
{
@@ -280,13 +301,13 @@ public:
//==============================================================================
/* The JUCEApplication::initialise method calls this function to allow the
child process to launch when the command line parameters indicate that we're
being asked to run as a child process..
being asked to run as a child process.
*/
bool invokeChildProcessDemo (const String& commandLine)
{
std::unique_ptr<DemoWorkerProcess> worker (new DemoWorkerProcess());
auto worker = std::make_unique<DemoWorkerProcess>();
if (worker->initialiseFromCommandLine (commandLine, demoCommandLineUID))
if (worker->initialiseFromCommandLine (commandLine, demoCommandLineUID, ChildProcessDemo::timeoutMillis))
{
worker.release(); // allow the worker object to stay alive - it'll handle its own deletion.
return true;
@@ -316,7 +337,7 @@ bool invokeChildProcessDemo (const String& commandLine)
if (invokeChildProcessDemo (commandLine))
return;
mainWindow.reset (new MainWindow ("ChildProcessDemo", new ChildProcessDemo()));
mainWindow = std::make_unique<MainWindow> ("ChildProcessDemo", std::make_unique<ChildProcessDemo>());
}
void shutdown() override { mainWindow = nullptr; }
@@ -325,13 +346,14 @@ bool invokeChildProcessDemo (const String& commandLine)
class MainWindow : public DocumentWindow
{
public:
MainWindow (const String& name, Component* c) : DocumentWindow (name,
Desktop::getInstance().getDefaultLookAndFeel()
.findColour (ResizableWindow::backgroundColourId),
DocumentWindow::allButtons)
MainWindow (const String& name, std::unique_ptr<Component> c)
: DocumentWindow (name,
Desktop::getInstance().getDefaultLookAndFeel()
.findColour (ResizableWindow::backgroundColourId),
DocumentWindow::allButtons)
{
setUsingNativeTitleBar (true);
setContentOwned (c, true);
setContentOwned (c.release(), true);
centreWithSize (getWidth(), getHeight());


Loading…
Cancel
Save