当没有waitForFinished()时,进程不发出信号
QProcess not emitting its signals when not waitForFinished()
在下面的代码中,省略waitForFinished()
将使QProcess停止发出信号。这到底有什么问题?这是Qt Bug吗?(5.7)。注意,此代码与QtConcurrent并行运行。但这不应该改变什么,不是吗?Afaik在其他线程中发送信号是可以的,尽管它们将被排队。
QProcess *process = new QProcess;
process->setReadChannel(QProcess::StandardOutput);
connect(process, &QProcess::readyReadStandardOutput, [](){
qDebug()<< "readyReadStandardOutput";
});
connect(process, &QProcess::stateChanged, [](QProcess::ProcessState state){
qDebug()<< "stateChanged"<< state;
});
connect(process, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
[=](){
qDebug()<< "finsished";
});
connect(process, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
[this, process](int exitCode, QProcess::ExitStatus exitStatus){
qDebug()<< "finsished";
if (exitStatus == QProcess::NormalExit && exitCode == 0){
while (process->canReadLine()) {
QString line = QString::fromLocal8Bit(process->readLine());
QRegularExpression regex(""(.*)" {(.*)}");
QRegularExpressionMatch match = regex.match(line);
names_.push_back(match.captured(1));
uuids_.push_back(match.captured(2));
}
}
process->deleteLater();
});
process->start("VBoxManage", {"list", "vms"});
process->waitForFinished(); // This line changes everything
qDebug()<< "leftWaitForFinished";
您没有在QProcess
实例所在的线程中运行事件循环。没有事件循环的线程中的任何QObject
都只是部分功能-计时器不会运行,队列调用不会交付等。所以你不能这么做。使用QObject
s和QtConcurrent::run
需要小心。
至少,只要进程存在,你应该有一个临时事件循环——在这种情况下,你应该按值保存QProcess
,因为在事件循环退出后,deleteLater
不会被执行。
QProcess process;
...
QEventLoop loop;
connect(process, &QProcess::finished, &loop, &QEventLoop::quit);
loop.exec();
否则,您需要将进程保持在一个更持久的线程中,并将该线程句柄(QThread
只是一个句柄!)保持在一个具有事件循环的线程中,该事件循环可以在完成时处理它。
// This can be run from a lambda that runs in an arbitrary thread
auto thread = new QThread;
auto process = new QProcess;
...
connect(process, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
[this, process](int exitCode, QProcess::ExitStatus exitStatus){
...
process->deleteLater();
process->thread()->quit();
});
process->start("VBoxManage", {"list", "vms"});
process->moveToThread(thread);
// Move the thread **handle** to the main thread
thread->moveToThread(qApp->thread());
connect(thread, &QThread::finished, thread, &QObject::deleteLater);
thread->start();
唉,这是非常愚蠢的,因为你正在创建临时线程,这是昂贵和浪费的。您应该有一个额外的工作线程,用于处理所有低开销的工作,例如QProcess
交互。该线程应该始终运行,并且您可以将所有QProcess
和类似的对象实例从并发lambda等移动到它。
相关文章:
- 父进程和子进程之间的 POSIX 信号量
- 进程过早退出,并发出 SIGSEGV 信号
- 在 Bash 脚本中处理来自子进程的信号
- 使用信号检测子进程何时终止的最佳方法是什么?
- 如何使用Windows API直接将进程"assign"到信号量?
- 子进程 c++ 的 Windows 控制台信号处理
- 如何防止在C++中使用 popen() 打开的进程接收 SIGINT 信号?
- 让 Gnu 屏幕将 SIGTERM 信号传递给子进程,允许它们干净地关闭
- 在父母获得杀死信号和退出后,用system()产生的儿童进程继续运行
- 在POSIX中,我可以保存信号以供调用条件等待的其他线程使用吗.(这些线程来自同一进程)
- 启动-停止守护进程启动的C程序无法捕获信号
- 在WINDOWS中从子进程向父进程发送信号
- 如何从一个进程向多个其他进程发送信号
- 使用SIGSEGV或SIGABRT信号转储核心并终止进程
- 用户空间和内核空间进程中的信号处理程序集
- C++ System V 信号量:多个服务器进程,一个客户端进程
- 互斥锁和信号量之间的区别 - 进程内和进程间
- 进程等待另一进程终止时的信号处理
- 如何在父进程中捕获Term动作信号
- 是否可以在Qt3.0中发出跨进程信号或发布触摸/鼠标点击事件