В основном потоке приложения с графическим интерфейсом я запускаю QProcess другого приложения с графическим интерфейсом, которое со временем будет регистрировать некоторые сообщения в стандартном выводе с помощью fputs(). Проблема в том, что через некоторое время приложение с графическим интерфейсом, запущенное с QProcess, зависнет, потому что его вывод не используется родителем. Я знаю, что это проблема, потому что, если я запускаю QProcess с аргументом QIODevice::NotOpen или QIODevice::Unbuffered, он не застрянет, но результат никогда не будет достигнут. Я пытался подключить сигналы readyRead, readyReadStandardError, readyReadStandardOutput подпроцесса к слоту в родительском элементе, но по некоторым причинам сигналы никогда не испускаются. Я также очищаю стандартный вывод после каждой записи. Мой вопрос: как заставить QProcess отправлять некоторые данные в режиме реального времени, не закрывая его?
Соединение сигналов (T- это оболочка для QProcess):
process->setWorkingDirectory(workingDir);
process->start(prog, argumentsList);
process->waitForStarted();
T* reciver = new V8QProcess(process);
QObject::connect(process, &QProcess::readyRead, reciver, &V8QProcess::OnMessageRecieved);
QObject::connect(process, &QProcess::readyReadStandardError, reciver, &V8QProcess::OnMessageRecieved);
QObject::connect(process, &QProcess::readyReadStandardOutput, reciver, &V8QProcess::OnMessageRecieved);
Код подпроцесса, который будет входить в stdout:
QByteArray bytes = LogMsg::getDisplayable(logMsg, 0).toUtf8();
fputs(bytes.constData(), stdout);
fflush(stdout);
Код OnMessageRecieved:
if (!p) { // p is the QProcess
return;
}
QByteArray output;
output.append(p->readAllStandardError()).append(p->readAll());
QString message = QString::fromStdString(output.toStdString());
Этот подход работает при запуске сценария оболочки или другой простой программы.
Да, я поставил точку останова.
Возможно, вам нужно соединить сигналы перед запуском QProcess.
До сих пор не видно улучшений...
Вы когда-нибудь звоните p->setReadChannel(...)
? Попробуйте заменить p->readAll()
на p->readAllStandardOutput
в V8QProcess::OnMessageRecieved
.
Просто не вызывайте блокирующие вызовы, такие как fputs
, из потока графического интерфейса в другом приложении. Создайте для этого отдельную ветку.
Я использовал setReadChannel(...)
для QProcess::StandardOutput
безрезультатно...
Графический интерфейс не зависает из-за fput()
, потому что он работает правильно в течение некоторого времени, в зависимости от количества журналов, а после этого он зависает, и если я убью родителя, дочерний элемент начнет работать как положено.
Я узнал, в чем проблема в моем случае:
Поскольку я запускал QProcess
в std::Thread
, происходящие события (сигналы) были пропущены, потому что std::Thread
не имеет очереди событий, как QThread
или QApplication
.
Решение, которое я использую:
1. Используйте QThread
вместо std::thread
2. Время от времени звоните QCoreApplication::proccesEvents()
.
Правильным решением является использование QThread::exec()
для создания event loop
, но этот подход заблокирует приложение с графическим интерфейсом, поэтому в моем случае это не годится.
Как вы думаете, почему сигналы
readyRead*
не излучаются? Вы установили точку останова в отладчике? Можете показать код дляV8QProcess::OnMessageRecieved
?