[SOLVED] child QProcess that dies with parent
-
G'day,
I'm working on a project which spawns a child process with QProcess. However, if the parent process terminates unexpectedly (program crash for example) the child process continues running. I'm wondering what the best method is for the child process to auto-terminate if the parent dies.
At the moment I'm using a 'heart-beat' approach, where the parent process notifies the child that it is still alive by sending an interprocess message. If the child doesn't receive these notifications, then it self-terminates. This isn't fool-proof, and I occasionally get false positives, etc. and I'm expecting it to be messy tuning the timeout parameters so it works across a bunch of different machines, under different loads, etc. It's also bad stewardship of the users battery. Further, I think OSX has become a lot more aggressive at suspending programs not in active use, so the parent is deprived of processing time to perform the heartbeat.
I was also thinking of passing the parents process ID to the child process as a command line argument, then the child could just periodically see if the parent process is still running. But I can't see a way to latch onto an existing process with QProcess.
Anyone have any suggestions?
many thanks
-
As long as you don't use QProcess:startDetached(), the process will be terminated when the parent dies.
-
bq. As long as you don’t use QProcess:startDetached(), the process will be terminated when the parent dies.
that's not what it does for me. i use start(), and if the process crashes the child process is not terminated. if the parent process terminates properly, then i agree, the child will be terminated, but i'm wanting to handle crashes too.
using OSX mavericks.
-
Ah sure, I've not read carefully.
-
Good day everyone.
I have same issue right now. My parent process creates child one with QProcess start() method. Then they work in pair: parent sends some commands to child via stdin, child sends some data via stdout and QSharedMemory back.
But when parent process crashes, child process keep running. I tried to implement heart-beat solution: every second parent writes 'live' to child's stdin, and child restarts it's inner timer; if no 'live' message coming for 5 seconds, child is going to exit:
@Child::Child()
{
...
connect(dieTimer, SIGNAL(timeout()), qApp, SLOT(quit()));
dieTimer->start(5000);
}void Child::keepAlive()
{
dieTimer->stop();
dieTimer->start(5000);
}void Child::readCommand()
{
std::string line;
std::getline(std::cin, line);if (line == "live") keepAlive(); else if ( ...
}
//----------------------
Parent::Parent()
{
....
connect(keepAliveTimer, SIGNAL(timeout()), SLOT(keepAlive()));
keepAliveTimer->start(1000);
}void Parent::keepAlive()
{
childProcess->write("live");
childProcess->write("\n");
}@But this solution isn't working. When parent crashes, child process became init's child and keep running (or probably freeze).
How can i handle parent's crash in Qt and quit?
I'm working on Ubuntu 13.10 with Qt 5.2.1 (but my app should work on Ubuntu, Windows and Mac OS, so Linux-specific ways does not suitable for me).
-
The idea and the published part of implementation look good.
I would use sockets instead of stdin/stdout but it is not important.[quote]When parent crashes, child process became init’s child and keep running (or probably freeze).[/quote]
Have you tried to debug child process when a parent process has crashed.
Why does it continue to reset the timer or where does it sits after the crash? -
I've solved this freezes. Problem was in
@std::getline(std::cin, line);@Reading from stdin is blocking operation so event loop became freezed here; i've run readCommand() method (with some fixes) in new QThread and problem has gone. Sockets is better solution, but this idea has not occurred to me. Thanks anyway.
Nevertheless, i'm wondering why Qt doesn't provides standard interface for these seemingly simple issues. Why child processes doesn't die with their parent and why i can't set up such behaviour?
-
hi, i tried something similar in solving this problem, but i could not get the heart-beat concept to work on OS X. however, i was using interprocess semaphores, and the issue may be specific to them.
the issue i had with heart-beats on OS X, is that if the program was in the background the heard-beats would stop. i think this reflects an aggressive power-saving strategy of OS X, where it suspends background processes.
my solution, which you may find more elegant, is as follows:
@
#ifdef WIN32
#include <windows.h>
#include <tlhelp32.h>
#else
#include "unistd.h"
#endifbool Process::isParentRunning()
{
#ifdef WIN32static unsigned long _parentPID = parentPID();
static void* _parentHandle = NULL;if (_parentHandle == NULL && _parentPID != 0)
_parentHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, _parentPID);if (_parentHandle != NULL)
{
BOOL success;
DWORD exitCode;success = GetExitCodeProcess(_parentHandle, &exitCode);
return ( ! success) || exitCode == STILL_ACTIVE;
}
#else
return getppid() != 1;
#endif
}
@ -
Thanks! Yes, this code is more elegant.
But mingw says that
@error: 'parentPID' was not declared in this scope@And i didn't found way to get parent PID under windows (although i can pass it via command line arguments). Is this code is working or just conceptual?
-
yes, this is working code from one my projects, the whole thing is:
process.h
@#ifndef PROCESS_H
#define PROCESS_Hclass Process
{
public:static unsigned long currentPID();
static unsigned long parentPID();static bool isParentRunning();
};
#endif // PROCESS_H
@process.cpp
@#include "process.h"
#ifdef WIN32
#include <windows.h>
#include <tlhelp32.h>
#else
#include "unistd.h"
#endifunsigned long Process::currentPID()
{
#ifdef WIN32
return GetCurrentProcessId();
#else
return getpid();
#endif
}unsigned long Process::parentPID()
{
#ifdef WIN32HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe = { 0 };
pe.dwSize = sizeof(PROCESSENTRY32);unsigned long pid = currentPID();
unsigned long ppid = 0;if( Process32First(h, &pe)) {
do {
if (pe.th32ProcessID == pid) {
ppid = pe.th32ParentProcessID;
break;
}
} while( Process32Next(h, &pe));
}CloseHandle(h);
return ppid;
#else
return getppid();
#endif
}bool Process::isParentRunning()
{
#ifdef WIN32static unsigned long _parentPID = parentPID();
static void* _parentHandle = NULL;if (_parentHandle == NULL && _parentPID != 0)
_parentHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, _parentPID);if (_parentHandle != NULL)
{
BOOL success;
DWORD exitCode;success = GetExitCodeProcess(_parentHandle, &exitCode);
return ( ! success) || exitCode == STILL_ACTIVE;
}return true;
#else
return getppid() != 1;
#endif
}
@