Reputation: 3864
I use a QProcess
for a lengthy calculation on a server. It may take only a few seconds or up to several hours and works fine as long as I let it finish on its own. However, I need to have the possibility to kill the process before it finishes which works fine only on my windows machine.
In linux, my QProcess
is killed and the processing of my data is executed sucessfully, but the child processes spawned by it remain. Here is an excerpt of my code:
// constructor
server::server(QObject* parent) : QTcpServer(parent)
{
this->calc_proc = new QProcess(this);
QObject::connect(this->calc_proc, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(calc_finished(int,QProcess::ExitStatus)));
...
}
void server::start_job(){
QString working_directory = "...";
QString input_file = "...";
QStringList arguments;
arguments << "memory=max" << "batch=no" << input_file;
this->calc_proc->setWorkingDirectory(working_directory);
this->calc_proc->start("path_to_external_program", arguments);
qDebug() << "Calc started with pid: " << this->calc_proc->pid();
}
void server::kill_job(){
this->calc_proc->terminate();
//this->calc_proc->kill();
}
The behaviour does not seem to differ when using terminate()
or kill()
. The child processes are children of my process to my knowledge:
Calc started with pid: 26395
ps ax
...
26441 pts/0 S 0:00 time /msc/MSC_Nastran/20131/msc20131/linux64/analysis
26442 pts/0 Rl 16:59 /msc/MSC_Nastran/20131/msc20131/linux64/analysis
...
ps -p 26442 -o ppid=
26441
ps -p 26441 -o ppid=
26395
My QProcess
returns his pid as 26395 which has a child 26441 which has a child 26442. So I'd expect that all of these are killed when I kill mine. As stated they survive. Is there any platform-independent way of killing these as well?
Upvotes: 1
Views: 3655
Reputation: 5478
Thx to @Bowdzone for the initial idea!
As the answer did not 100 percent work for me, because my parent spawns more than one child process, I've adjusted it a bit to this method:
void CameraReceiver::stopChildProcesses(qint64 parentProcessId) {
qDebug() << "stopChildProcesses for parent id:" << parentProcessId;
QProcess get_childs;
QStringList get_childs_cmd;
get_childs_cmd << "--ppid" << QString::number(parentProcessId) << "-o" << "pid" << "--no-heading";
get_childs.start("ps", get_childs_cmd);
get_childs.waitForFinished();
QString childIds(get_childs.readAllStandardOutput());
childIds.replace('\n', ' ');
QProcess::execute("kill " + childIds);
}
Then I can simply call the following:
stopChildProcesses(parentProcess.processId());
Upvotes: 1
Reputation: 3864
user4419802 brought me on the correct track. In Linux, killing a process does not kill its children. They are moved up and continue without having a parent anymore.
Generally you'd want to save all pids
of children when spawning them (and there are multiple answers telling you how to do so) but that was not possible in my case as I am not spawning the children but the external application I call does so without my knowledge. So I came up with the following solution which works good for me:
QProcess* main_process = new QProcess(this);
...
// linux: a child is spawned which is not killed with its parent
// therefore the process id is retrieved and the process killed independently
#if defined(Q_OS_LINUX)
QProcess get_child_a;
QStringList get_child_a_cmd;
get_child_a_cmd << "--ppid" << QString::number(main_process->processId()) << "-o" << "pid" << "--no-heading";
get_child_a.start("ps", get_child_a_cmd);
get_child_a.waitForFinished(5000);
QString child_a_str = get_child_a.readAllStandardOutput();
int child_a = child_a_str.toInt();
QProcess::execute("kill " + QString::number(child_a));
#endif
// windows & linux: kill main process
main_process->kill();
In my case, I know that only one child process id is returned so the parsing of the get_child
process output is a straightforward cast.
Upvotes: 3
Reputation: 15196
QProcess::kill()
is just SIGKILL
. So it's not about Qt, but about Unix process management.
You can read on that issue How to make child process die after parent exits?
Upvotes: 2