QProcess застрял - PullRequest
       17

QProcess застрял

2 голосов
/ 25 февраля 2011

У меня есть следующее небольшое приложение.Запуск Qt с компилятором MinGW в 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;
}

Несмотря на все усилия, после запуска этой программы я получаю только один вывод:

QProcess: Destroyed while process still running

Я не знаю, делаю ли ячто-то не так, или я что-то упускаю.Я изменил вызов waitForFinished на waitForReadyRead Я сам установил канал чтения, но все безрезультатно.Теперь мне официально нужна помощь, так как я не хочу реализовывать свой собственный grep.

Ответы [ 2 ]

5 голосов
/ 25 февраля 2011

Как правило, вы не хотите запускать процесс и накапливать all его вывод в системный канал перед попыткой чтения.Известно, что это вызывает взаимные блокировки, особенно в Windows.

Система накладывает ограничение на размер буфера для канала.Что происходит, так это то, что дочерний процесс (grep) блокирует запись в канал, потому что буфер заполнен.Он ожидает, пока родительский процесс (ваше приложение) прочитает из канала, освобождая место в буфере.Теперь, поскольку ваши приложения находятся в состоянии ожидания блокировки, ожидая завершения процесса, каждое из них ожидает друг за другом.

Поскольку waitForFinish() по умолчанию ожидает не более 30 секунд, в конце 30секунд, ваше приложение прерывает ожидание блокировки и возвращается, дочерний процесс все еще выполняется, и вы уничтожаете его.

Решением этой проблемы является активный цикл чтения для обработки выходных данных дочернего процесса по мере его создания, обеспечиваясвободное место в буфере и, таким образом, предотвращение взаимоблокировки.

Я не специалист по Qt, поэтому я не уверен, как реализовать этот активный цикл в Qt.Взглянув на документацию для QProcess, я бы сказал что-то вроде:

    // 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.
0 голосов
/ 25 февраля 2011

Пара вещей:

1) вам, вероятно, следует вызвать waitForStarted () после запуска, чтобы дождаться его запуска и запуска.

2) вы не хотите вызывать waitForFinished() вверху, потому что он будет ждать, пока это не будет сделано (по умолчанию ожидание в течение 30 секунд).

3) Возможно, вы действительно захотите вызвать waitForFinished () в конце после того, как закончите поисквывод (в большинстве ОС вы должны позволить процессу возвращать правильный статус завершения и ждать его; на самом деле я не уверен, как Qt справляется с этим, если честно, и нужно ли вам выполнять waitForFinished () в вышестоящем коде илипозволит ли нижний код Qt игнорировать это требование)

...