简体   繁体   English

终止QProcess不会杀死子进程

[英]Terminating QProcess doesn't kill child process

I have the following Problem: I have a Qt GUI-Application (c++) which starts an external java application via a bash-script. 我有以下问题:我有一个Qt GUI应用程序(c ++),它可以通过bash脚本启动外部Java应用程序。 When I terminate my QProcess the script is killed, but the child-process (the java-application) is still running. 当我终止QProcess时,脚本被杀死,但是子进程(java应用程序)仍在运行。

I don't understand this behavior, because if I run the script in terminal and kill it, the child process is also killed. 我不了解这种行为,因为如果我在终端中运行脚本并将其杀死,则子进程也会被杀死。 Maybe it has something to do with the various event loops in Qt, which I have not understood yet. 也许这与Qt中的各种事件循环有关,但我还不了解。


Here is my code: 这是我的代码:

MainWindow.h MainWindow.h

#include <QMainWindow>
#include <QProcess>

namespace Ui {
  class MainWindow;
}

class MainWindow : public QMainWindow
{
  Q_OBJECT
public:
  explicit MainWindow(QWidget *parent = nullptr);
  ~MainWindow();

private slots:
  void slot_startQProcess();
  void slot_killQProcess();

private:
  Ui::MainWindow *ui;

  QProcess myProcess;
};

MainWindow.cpp MainWindow.cpp

#include "MainWindow.h"
#include "ui_MainWindow.h"

MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent),
  ui(new Ui::MainWindow)
{
  ui->setupUi(this);
  connect(ui->pb_start, &QPushButton::clicked, this, &MainWindow::slot_startQProcess);
  connect(ui->pb_kill, &QPushButton::clicked, this, &MainWindow::slot_killQProcess);
}

MainWindow::~MainWindow()
{
  delete ui;
}

void MainWindow::slot_startQProcess()
{
  myProcess.setWorkingDirectory("./i2exrep");
  myProcess.start("./myScript.sh");
}

void MainWindow::slot_killQProcess()
{
  myProcess.close();
}

main.cpp main.cpp中

#include "MainWindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  MainWindow w;
  w.show();
  return a.exec();
}

myScript.sh myScript.sh

#!/bin/csh
java -jar i2exrep.jar

Folder structure: 资料夹结构:

  • .pro File .pro文件
  • *.cpp *的.cpp
  • *.h *。H
  • i2exrep (Folder) i2exrep(文件夹)
    • myScript.sh myScript.sh

So my application starts "myScript.sh" which starts "java -jar i2exrep.jar" 所以我的应用程序启动了“ myScript.sh”,启动了“ java -jar i2exrep.jar”

Killing the QProcess only terminates "myScript.sh", but "java -jar i2exrep.jar" is still running. 杀死QProcess只会终止“ myScript.sh”,但“ java -jar i2exrep.jar”仍在运行。 - i2exrep.jar -i2exrep.jar


EDIT: 编辑:

I tried the same with another main function: 我尝试了另一个主要功能相同:

#include <QCoreApplication>
#include <QProcess>
int main(int argc, char *argv[])
{
  QCoreApplication a(argc, argv);
  QProcess myProcess;
  myProcess.setWorkingDirectory("./i2exrep");
  myProcess.start("./myScript.sh");
  return a.exec();
}

When I quit this program, then the Java application is also terminated. 当我退出该程序时,Java应用程序也将终止。 When I finish the first program (the GUI application), then only the script is terminated and the Java application continues to run. 当我完成第一个程序(GUI应用程序)时,只有脚本终止并且Java应用程序继续运行。 I get the following error message: 我收到以下错误消息:

QProcess: Destroyed while process ("./myScript.sh") is still running.

I assume you run some UNIX system (since the shell and / path separator). 我假设您运行了一些UNIX系统(由于shell和/路径分隔符)。

Do you really need both processes (the shell and java)? 您是否真的需要两个进程(shell和Java)? Maybe leaving only java will solve your problem. 也许只留下java将解决您的问题。 Add exec to your script: exec添加到脚本中:

#!/bin/csh
exec java -jar i2exrep.jar

My guess is that when you run your application in a terminal and then close it, all child processes receive SIGHUP since they lose the controlling terminal. 我的猜测是,当您在终端中运行应用程序然后关闭它时,所有子进程都会收到SIGHUP,因为它们失去了控制终端。 When you run the script from GUI application there is no controlling terminal at the first place, so java won't terminate on quit. 从GUI应用程序运行脚本时,首先没有控制终端,因此Java不会在退出时终止。 Anyway, the correct way to terminate a child process is to send it a signal (SIGTERM, maybe SIGKILL after some time) and then wait(2) it's termination. 无论如何,终止子进程的正确方法是向其发送信号(SIGTERM,或者一段时间后可能是SIGKILL),然后等待其终止(2)。

If you don't want to get rid from a shell process in your process chain, see this answer to find out how to forward signals to child process in shell. 如果您不想摆脱流程链中的Shell流程,请查看此答案以了解如何将信号转发到Shell中的子流程。

I solved it by using setsid to start the process. 我通过使用setsid来启动进程来解决了。

Please, check the example below: 请检查以下示例:

process->start("setsid ./example.sh");
(...)
QString killingProcess = "kill -TERM -" + QString::number(process->pid());
system(killingProcess.toStdString().c_str());

For more details, please, visit this link. 有关更多详细信息,请访问链接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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