stdout from QProcess is nowhere near realtime - qt

I want to get the stdout from a QProcess into a QTextEdit.
It works if I do it like this:
QObject::connect(process, SIGNAL(readyReadStandardOutput()),
this, SLOT(readStdOutput()));
and
void myClass::readStdOutput()
{
teOutput->insertPlainText(process->readAllStandardOutput());
}
While the subprogramm continuously prints to stdout (tested in a terminal)
the QTextEdit is only updated every couple of seconds with chunks of output.

From the QIODevice manual:
Certain subclasses of QIODevice, such as QTcpSocket and QProcess, are asynchronous. This means that I/O functions such as write() or read() always return immediately, while communication with the device itself may happen when control goes back to the event loop. QIODevice provides functions that allow you to force these operations to be performed immediately, while blocking the calling thread and without entering the event loop.
Another thing to try would be to disable any buffer, the manual doesn't mention it for QProcess, but you could try it:
Some subclasses, such as QFile and QTcpSocket, are implemented using a memory buffer for intermediate storing of data. This reduces the number of required device accessing calls, which are often very slow.
...
QIODevice allows you to bypass any buffering by passing the Unbuffered flag to open().

Calling waitForReadyRead() seems to trigger an update.
So, to update e.g. 10 times per second, after
QObject::connect(process, SIGNAL(readyReadStandardOutput()),
this, SLOT(readStdOutput()));
add a
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(executeWaitForReadyRead()));
timer->start(100);
and
void YourClass::executeWaitForReadyRead()
{
process->waitForReadyRead();
}

Related

How to read QProcess output

In the main thread of a Gui Application I am starting a QProcess of another GUI application that will log some messages over time in stdout using fputs(). The problem is that after some time the GUI application started with QProcess will freeze because it's output is not consumed by the parent. I know that this is the problem because if I am starting the QProcess with QIODevice::NotOpen or QIODevice::Unbuffered argument, it will not get stuck but the output will never be reached.
I've tried to connect the readyRead, readyReadStandardError, readyReadStandardOutput signals of the subprocess to a slot in the parent, but for some reasons the signals are never emitted. I am also flushing the stdout after each write.
My question is how to force QProcess to send some data in real time without closing it?
The connection of the signals, (T- is a wrapper for 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);
The code of the subprocess that will log in stdout:
QByteArray bytes = LogMsg::getDisplayable(logMsg, 0).toUtf8();
fputs(bytes.constData(), stdout);
fflush(stdout);
The code of the OnMessageRecieved:
if (!p) { // p is the QProcess
return;
}
QByteArray output;
output.append(p->readAllStandardError()).append(p->readAll());
QString message = QString::fromStdString(output.toStdString());
This approach is working when running a shell script or other simple program.
I found out what the problem was on my case:
Because I was starting the QProcess in a std::Thread, the events(signals) that occur were skipped because std::Thread don't have a queue of events as QThread or QApplication does.
The solution that I use is:
1. Use QThread instead of std::thread
2. Call QCoreApplication::proccesEvents() from time to time.
The proper solution is to use QThread::exec() in order to create an event loop, but this approach would block the GUI Application, so in my case is no good.

QProcess state() always returns RUNNING

I do the following to start a process and waits for its completion (I am intentionally avoiding use of SIGNAL/SLOTS in this case).
QProcess *myProcess = new QProcess();
QString program = "test.exe";
QStringList args;
myProcess->start(program, args);
myProcess->waitForStarted();
while( myProcess->state() == QProcess::Running )
{
// Do other things...
}
I can verify that test.exe exits. But process state is for some reason always QProcess::Running. I am using Qt 4.8.2 on Windows.
If "do other things" does not include processing events of the thread's event loop, then the QProcess never gets a chance to update its state.
Either waitForFinished if this needs to block the thread or connect to the finished() signal.
I don't think state() should be used to check for a program that has closed down but you can use something like while(!waitForFinished(1)).

How to run a synchronous chain of QProcess without freezing the gui?

I want to optimize images with the help of some external programs. The programs must be executed one after one, some of them depending on the output of the last program, some of them depending on the characteristics of the image.
I know, I can use signals, but this is not very useful here, because I would have to use dozens of functions and signals for each and every external program, some of them even multiple times depending on the position, where a program is called in the chain. It would be much easier to execute them one by one. But if I do so, the gui freezes immidiately even without displaying the status message until all processes are finished. What else can I do?
ui->status->setText("Do something with program 1");
QProcess *proc1 = new QProcess;
proc1->setReadChannelMode(QProcess::SeparateChannels);
proc1->start("program 1 -args", QIODevice::ReadWrite);
while(!proc1->waitForFinished(10))
;
ui->status->setText("Do something with program 2");
QProcess *proc2 = new QProcess;
proc2->setReadChannelMode(QProcess::SeparateChannels);
proc2->start("program 2 -args", QIODevice::ReadWrite);
while(!proc2->waitForFinished(10))
;
In this case using Signals is the "correct" way. You just need to chain them.
[...]
ui->status->setText("Do something with program 1");
proc1.setReadChannelMode(QProcess::SeparateChannels);
proc1.start("program 1 -args", QIODevice::ReadWrite);
connect(proc1, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(finishedProc1()))
[...]
void finishedProc1()
{
ui->status->setText("Do something with program 2");
proc2.setReadChannelMode(QProcess::SeparateChannels);
proc2.start("program 2 -args", QIODevice::ReadWrite);
connect(proc2, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(finishedProc2()))
}
void finishedProc2()
{
[...]
}
Alternativly you could call processEvents in QApplication while you are waiting or do the whole thing in a different QThread.
Create worker thread (several threads, if you need parallel processing) and do waiting there. GUI will not be blocked then.

QProcess.startDetached() and write to its stdin

What is wrong with this code? I can not write to stdin of new process that has been detached.
It is important for me that the new process is detached.
QProcess commandLine;
commandLine.setWorkingDirectory("E:\\"); //does not work.
commandLine.startDetached("cmd.exe"); //works (but uses wrong working dir).
commandLine.write("echo hi\0"); //writes nothing.
commandLine.write("\n\r"); //Still nothing is written!
Good morning.
The problem is that QProcess::startDetached() is a static method which creates a "fire and forget" process.
This means, that you cannot set a working directory this way. All you can do is call
QProcess::startDetached (const QString &program, const QStringList &arguments, const QString &workingDirectory);
This however leaves you with the problem of writing to the stdin of the newly created process. The thing is, since you don't have a QProcess object there is nothing you can write your stdin to. There could be a solution using the process handle the static startDetached() method's providing.
We had the similar problem in our company. We needed detached processes which ran beyond the lifespan of the calling programm and for which we could set the environment. This seemed, looking at the Qt code, impossible.
My solution was to use a wrapper around QProcess with its own startDetached() method.
What it did, it actually created this QProcess subclass on the heap and used its ordinary start() method. In this mode however the signal, which fires once the process has finished, calles upon a slot which deletes the object itself: delete this;. It works. The process is running independently and we can set an environment.
So basically there is no need to use the detached start method. You can use the ordinary start method as long as your QProcess is an object on the heap. And if you care for memory leaks in this scenario you'd have to provide a similar mechanism as described above.
Best regards
D
call static method with arguments doesn't provide any set of process into child command.
process.startDetached(command)
try this:
QProcess process;
process.setProgram(fileName);
process.setArgument(argsList);
process.setWorkingDirectory(dirName);
process.startDetached();

Restore serial port attributes even after control-C?

When using a serial port via POSIX, it's recommended to save the original attributes using tcgetattr() before changing them with tcsetattr(), and then restore them before closing the port. What about when a program is terminated by pressing control-C or when the program receives SIGINT? I haven't seen this covered in any of the serial tutorials.
Apparently an atexit() function wouldn't be sufficient, because it's not called by the default SIGINT handler. So it seems installation of a signal handler would be necessary that restores the attributes to any serial ports still open. Is it even safe to call tcsetattr() from a signal handler?
One might simply dismiss this issue as insignificant, but it's common to terminate a program with control-C, especially one that can take tens of seconds to complete operations. If it's OK not to preserve serial port settings in this case, then there seems little reason to preserve them at all. If anything, it might be better not to bother, rather than do it inconsistently.
I found some examples of source code doing the above, but nothing well-documented. I guess I'm interested in some discussion of whether this is a good idea. Thanks.
After further research I think I've answered this to my satisfaction.
First, in the man page for signal I noticed that a signal handler is specifically allowed to call tcsetattr(), along with a few others:
The signal handler routine must be very careful, since processing elsewhere was interrupted at some arbitrary point. POSIX has the concept of "safe function". If a signal interrupts an unsafe function, and handler calls an unsafe function, then the behavior is undefined. Safe functions are listed explicitly in the various standards. The POSIX.1-2003 list is ... `raise()` ... `signal()` ... `tcsetattr()` [trimmed to relevant ones]
This strongly suggests that the POSIX committee had this exact kind of thing in mind, and leads to a straight forward approach where you change the SIGINT handler once you've opened serial and saved its attributes, then in your handler, restore them and the old SIGINT handler, then re-raise the signal:
static void (*prev_sigint)( int );
static termios saved_attr;
static int fd;
static void cleanup( int ignored )
{
tcsetattr( fd, TCSANOW, &saved_attr );
signal( SIGINT, prev_sigint );
raise( SIGINT );
}
int main( void )
{
open_serial_and_save_attrs();
prev_sigint = signal( SIGINT, cleanup );
...
}

Resources