在不同的 QThread 中杀死 QProcess 运行
Kill a QProcess running in a different QThread
我有一个 class 继承了 QThread
并且我重新实现了 run()
方法。在这个 运行 方法中,有一个 QProcess
(在 运行 中声明)启动一个程序。
现在,如果我在该进程仍在 运行ning 时关闭我的应用程序,它实际上不会关闭,直到进程完成。
所以我的问题是如何停止这个过程?
根据我在 Qt 文档中阅读的内容,我不能在此处使用 signal/slot,因为我的进程将与不是主线程的线程具有线程关联性,因此连接会排队,而这不会'不要停止我的进程。
我正在使用 Qt 5.8
提前致谢!
编辑:这是线程代码,如果您需要更多,请告诉我
void run()
{
QString cmd;
QProcess p;
connect(&p, SIGNAL(finished(int)), this, SLOT(quit()));
//connect(this, SIGNAL(signalTerminateProcess()), &p, SLOT(kill())); // queued connect that doesn't kill my process
p.start(cmd);
if(p.waitForFinished(-1))
{
qInfo("process done");
}
}
首先,您可以跨 QThreads 使用信号和插槽,甚至可以使用 Qt::BlockingQueuedConnection
等待插槽执行。参见 Qt documentation。
但是,这需要目标 QObject 存在于具有 运行 事件循环的线程中。在你的例子中,因为你已经超载了 QThread::run()
,你不会有一个事件循环。
据我所知,您有 2 种方法来修复您的代码,要么进行小的修复,要么更改设计并使用事件循环。
1。快速修复
void run()
{
QString cmd;
QProcess p;
connect(&p, SIGNAL(finished(int)), this, SLOT(quit()));
//connect(this, SIGNAL(signalTerminateProcess()), &p, SLOT(kill())); // queued connect that doesn't kill my process
p.start(cmd);
while(! p.waitForFinished(100)) //Wake up every 100ms and check if we must exit
{
if (QThread::currentThread()->isInterruptionRequested())
{
p.terminate();
if (! p.waitForFinished(1000))
p.kill()
break;
}
}
qInfo("process done");
}
int cleanUp()
{
thread->requestInterruption();
thread->wait();
}
或
QProcess *process = nullptr;
void run()
{
QString cmd;
QProcess p;
process = &p; //You shouldn't do that in real code
connect(&p, SIGNAL(finished(int)), this, SLOT(quit()));
//connect(this, SIGNAL(signalTerminateProcess()), &p, SLOT(kill())); // queued connect that doesn't kill my process
p.start(cmd);
while(! p.waitForFinished(100)) //Wake up every 100ms and check if we must exit
{
QCoreApplication::processEvents();
}
qInfo("process done");
process = nullptr;
}
int cleanUp()
{
QTimer::singleShot(0, process, &QProcess::terminate);
// Qt 5.10 -> QMetaObject::invokeMethod(process, &QProcess::terminate);
if (! thread->wait(1000))
{
QTimer::singleShot(0, process, &QProcess::kill);
thread->wait();
}
}
2。事件循环修复
// Create thread
QThread thread;
thread.start();
// Create process and move it to the other thread
QProcess process;
process.moveToThread(&thread);
void startProcess()
{
p.start(cmd);
}
QMutex mutex;
void stopProcess()
{
p.terminate();
if (!p.waitForFinished(1000))
p.kill();
p.moveToThread(qApp->thread());
mutex.unlock();
}
// Call startProcess() in the other thread
QTimer::singleShot(0, &process, &startProcess);
// Call stopProcess() in the other thread
mutex.lock();
QTimer::singleShot(0, &process, &stopProcess);
mutex.lock();
thread.quit();
if (!thread.wait(100))
thread.terminate();
你可以:
- 使用原子或使用与
Qt::BlockingQueuedConnection
连接的信号替换互斥量。
- 用插槽和 lambda 替换
startProcess()
和 stopProcess()
。
- 将对
QTimer::singleShot()
的调用替换为 QMetaObject::invokeMethod()
或使用信号。 请注意,您可以将 Qt::BlockingQueuedConnection
与 QMetaObject::invokeMethod()
一起使用
我有一个 class 继承了 QThread
并且我重新实现了 run()
方法。在这个 运行 方法中,有一个 QProcess
(在 运行 中声明)启动一个程序。
现在,如果我在该进程仍在 运行ning 时关闭我的应用程序,它实际上不会关闭,直到进程完成。
所以我的问题是如何停止这个过程?
根据我在 Qt 文档中阅读的内容,我不能在此处使用 signal/slot,因为我的进程将与不是主线程的线程具有线程关联性,因此连接会排队,而这不会'不要停止我的进程。
我正在使用 Qt 5.8
提前致谢!
编辑:这是线程代码,如果您需要更多,请告诉我
void run()
{
QString cmd;
QProcess p;
connect(&p, SIGNAL(finished(int)), this, SLOT(quit()));
//connect(this, SIGNAL(signalTerminateProcess()), &p, SLOT(kill())); // queued connect that doesn't kill my process
p.start(cmd);
if(p.waitForFinished(-1))
{
qInfo("process done");
}
}
首先,您可以跨 QThreads 使用信号和插槽,甚至可以使用 Qt::BlockingQueuedConnection
等待插槽执行。参见 Qt documentation。
但是,这需要目标 QObject 存在于具有 运行 事件循环的线程中。在你的例子中,因为你已经超载了 QThread::run()
,你不会有一个事件循环。
据我所知,您有 2 种方法来修复您的代码,要么进行小的修复,要么更改设计并使用事件循环。
1。快速修复
void run()
{
QString cmd;
QProcess p;
connect(&p, SIGNAL(finished(int)), this, SLOT(quit()));
//connect(this, SIGNAL(signalTerminateProcess()), &p, SLOT(kill())); // queued connect that doesn't kill my process
p.start(cmd);
while(! p.waitForFinished(100)) //Wake up every 100ms and check if we must exit
{
if (QThread::currentThread()->isInterruptionRequested())
{
p.terminate();
if (! p.waitForFinished(1000))
p.kill()
break;
}
}
qInfo("process done");
}
int cleanUp()
{
thread->requestInterruption();
thread->wait();
}
或
QProcess *process = nullptr;
void run()
{
QString cmd;
QProcess p;
process = &p; //You shouldn't do that in real code
connect(&p, SIGNAL(finished(int)), this, SLOT(quit()));
//connect(this, SIGNAL(signalTerminateProcess()), &p, SLOT(kill())); // queued connect that doesn't kill my process
p.start(cmd);
while(! p.waitForFinished(100)) //Wake up every 100ms and check if we must exit
{
QCoreApplication::processEvents();
}
qInfo("process done");
process = nullptr;
}
int cleanUp()
{
QTimer::singleShot(0, process, &QProcess::terminate);
// Qt 5.10 -> QMetaObject::invokeMethod(process, &QProcess::terminate);
if (! thread->wait(1000))
{
QTimer::singleShot(0, process, &QProcess::kill);
thread->wait();
}
}
2。事件循环修复
// Create thread
QThread thread;
thread.start();
// Create process and move it to the other thread
QProcess process;
process.moveToThread(&thread);
void startProcess()
{
p.start(cmd);
}
QMutex mutex;
void stopProcess()
{
p.terminate();
if (!p.waitForFinished(1000))
p.kill();
p.moveToThread(qApp->thread());
mutex.unlock();
}
// Call startProcess() in the other thread
QTimer::singleShot(0, &process, &startProcess);
// Call stopProcess() in the other thread
mutex.lock();
QTimer::singleShot(0, &process, &stopProcess);
mutex.lock();
thread.quit();
if (!thread.wait(100))
thread.terminate();
你可以:
- 使用原子或使用与
Qt::BlockingQueuedConnection
连接的信号替换互斥量。 - 用插槽和 lambda 替换
startProcess()
和stopProcess()
。 - 将对
QTimer::singleShot()
的调用替换为QMetaObject::invokeMethod()
或使用信号。 请注意,您可以将Qt::BlockingQueuedConnection
与QMetaObject::invokeMethod()
一起使用