简体   繁体   中英

QProcess::kill() does not kill children in linux

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?

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.

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?

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());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM