В основном потоке приложения с графическим интерфейсом я запускаю 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?