Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QProcess is stuck

Tags:

c++

mingw

qt4

I have the following small application. Running Qt with MinGW compiler in Windows 7

#include <QProcess>
#include <QStringList>
#include <iostream>

const int64_t kBuffSize = 2048;

int main(int argc, char *argv[]) {
  QProcess grep;
  QStringList params;
  params << "-e" << "\".*pas'\"" << "\"Path to file\"";
  grep.start("C:\\MinGW\\msys\\1.0\\bin\\grep.exe", params);
  grep.setReadChannel(QProcess::StandardOutput);
  if (!grep.waitForFinished()) {
    if (grep.state() == QProcess::Running)
      grep.kill();
    return 1;
  }
  std::cout << "ready to read"  << std::endl;
  char buffer[kBuffSize];
  while (grep.readLine(buffer, kBuffSize) > 0) {
    std::cout << buffer;
  }
  if (grep.state() == QProcess::Running)
    grep.kill();
  return 0;
}

Despite all efforts, after running this program the only output I get is:

QProcess: Destroyed while process still running

I don't know if I am doing something wrong, or I am missing something. I have change the waitForFinished call for waitForReadyRead I setted up the read channel myself, all to no avail. Now I officially need help since I don't want to implement my own grep.

like image 745
Sambatyon Avatar asked Mar 19 '26 19:03

Sambatyon


1 Answers

As a general fashion, you don't want to run a process and accumulate all it's output in a system pipe before trying to read. This is know to cause deadlocks, especially on Windows.

The system imposes a limit on the buffer size for the pipe. What happens is that the child process (grep) blocks on a write to the pipe because the buffer is full. It waits for the parent process (you app) to read from the pipe, freeing space in the buffer. Now, since your applications is in a blocking wait, waiting for the process to finish, they're each waiting after each other.

Because waitForFinish() waits at most 30 seconds by default, at the end of 30 seconds, your application breaks the blocking wait and returns, the child process is still running and you kill it.

The solution to this problem is an active read loop to process the child process output as it is generated, ensuring free space in the buffer and thus preventing the deadock.

I'm no expert in Qt, so I'm not sure how to implement this active loop in Qt. Taking a look at the documentation for QProcess, I'd say something like:

    // Use resizable buffers, unlike the system.
QByteArray stderr;
QByteArray stdout;

    // Give the child process some time to start.
grep.waitForStarted();
do {
        // Read all available data on both output streams.
    stderr += grep.readAllStandardError();
    stdout += grep.readAllStandardOutput();
}
    // Wait 100 ms and keep looping if not finished.
while ( !grep.waitForFinished(100) );

    // Make sure you catch any leftovers.
stderr += grep.readAllStandardError();
stdout += grep.readAllStandardOutput();

// Do something with the buffers.
like image 110
André Caron Avatar answered Mar 22 '26 13:03

André Caron