QProcess не выдает свои сигналы, когда не waitForFinished()
В следующем коде опущено waitForFinished()
заставляет QProcess перестать излучать свой сигнал. Какого черта с этим не так? Это Qt Bug? (5.7). Обратите внимание, что этот код запускается параллельно с QtConcurrent run. Но это ничего не должно изменить, не так ли? 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";
1 ответ
Вы не запускаете цикл обработки событий в потоке, где QProcess
Экземпляр живет. любой QObject
в потоке без цикла обработки событий функционирует только частично - таймеры не будут работать, вызовы в очереди не будут доставляться и т. д. Поэтому вы не можете этого сделать. С помощью QObject
с 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
и подобные ему экземпляры объектов из параллельных лямбд и т. д.