Как правильно использовать QProcess write?
Мне нужна программа для связи с подпроцессом, который полагается на in-и
выход. Проблема в том, что я, по-видимому, не могу правильно использовать QProcess.
Далее код должен создать QProcess, запустить его и войти в основной цикл while. Там он выводит все выходные данные, созданные подпроцессом, на консоль и затем запрашивает у пользователя входные данные, которые затем передаются подпроцессу через write(...).
Первоначально у меня было две проблемы, вытекающие из этого сценарий:
- подпроцесс
printfне может быть прочитан родительским процессом.
scanfв подпроцессе не принимаются строки, отправленные черезwrite.
Что касается (1), я понял, что это проблема, вызванная буферизацией stdout подпроцесса. Эта проблема может быть легко решена с помощью fflush(stdout) вызовов или манипуляций относительно его поведения при промывке.
Вторая проблема-это та, с которой я не могу справиться.
write вызывается и даже возвращает правильное количество отправленных байтов. Однако подпроцесс не продолжает свое извлечение, поскольку в его выходные данные не записываются новые данные. Похоже, что scanf не получает отправленные данные. Выходные данные, полученные программой, следующие: Subprocess should have started.
124 bytes available!
Attempting to read:
Read: This is a simple demo application.
Read: It solely reads stdin and echoes its contents.
Read: Input exit to terminate.
Read: ---------
Awaiting user input: test
Written 5 bytes
No line to be read...
Awaiting user input:
Я серьезно застрял прямо здесь. Тяжелое мышление Google + потерпело неудачу на мне, я хочу передать это вам как мой последний маяк надежды. В случае, если я просто не вижу леса из-за всех деревьев, мои извинения.
В случае, если эта информация необходима: я работаю на 64-битном MacOS X, используя Qt5 и компилятор clang. Подпроцесс-код компилируется с помощью gcc на той же машине.
Заранее большое вам спасибо,
NR
Главный Код:
int main() {
// Command to execute the subprocess
QString program = "./demo";
QProcess sub;
sub.start(program, QProcess::Unbuffered | QProcess::ReadWrite);
// Check, whether the subprocess is starting correctly.
if (!sub.waitForStarted()) {
std::cout << "Subprocess could not be started!" << std::endl;
sub.close();
return 99;
}
std::cout << "Subprocess should have started." << std::endl;
// Check, if the subprocess has written its starting message to the output.
if (!sub.waitForReadyRead()) {
std::cout << "No data available for reading. An error must have occurred." << std::endl;
sub.close();
return 99;
}
while (1) {
// Try to read the subprocess' output
if (!sub.canReadLine()) {
std::cout << "No line to be read..." << std::endl;
} else {
std::cout << sub.bytesAvailable() << " bytes available!" << std::endl;
std::cout << "Attempting to read..." << std::endl;
while (sub.canReadLine()) {
QByteArray output = sub.readLine();
std::cout << "Read: " << output.data();
}
}
std::cout << "Awaiting user input: ";
std::string input;
getline(std::cin, input);
if (input.compare("exit") == 0) break;
qint64 a = sub.write(input.c_str());
qint64 b = sub.write("n");
sub.waitForBytesWritten();
std::cout << "Written " << a + b << " bytes" << std::endl;
}
std::cout << "Terminating..." << std::endl;
sub.close();
}
Подпроцесс-Код:
int main() {
printf("This is a simple demo application.n");
printf("It reads stdin and echoes its contents.n");
printf("Input "exit" to terminate.n");
while (1) {
char str[256];
printf("Input: ");
fflush(stdout);
scanf("%s", str);
if (strcmp(str, "exit") == 0) return 0;
printf("> %sn", str);
}
}
P. s: поскольку это мой первый вопрос по SO, пожалуйста, скажите мне, если что-то не так в отношении стиля задавания вопросов.
Решение
После многих еще много проб и ошибок, и мне удалось найти решение этой проблемы. Добавление вызова в waitForReadyRead() заставляет основной процесс ждать, пока новый вывод не будет записан подпроцессом. Рабочий код:
...
sub.waitForBytesWritten();
std::cout << "Written " << a + b << " bytes" << std::endl;
// Wait for new output
sub.waitForReadyRead();
...
Я до сих пор понятия не имею, почему это работает таким образом. Я предполагаю, что это как-то связано с блокировкой основного процесса getline() против блокировки waitForReadyRead(). Мне кажется, что getline() блокирует все, включая подпроцесс, в результате чего вызов scanf никогда не будет обработано из-за условий гонки.
Было бы здорово, если бы кто-то, кто понимает, мог отказаться от объяснения.
Спасибо за помощь :)
NR
1 ответ:
Это не сработает. Вы ждете, что отправленные байты будут записаны, но вы не ждете Эхо. Вместо этого вы вводите функцию getline (), ожидая ввода нового пользователя. Имейте в виду, что здесь задействованы два процесса, где каждый процесс может быть отложен в любой степени.
Кроме того, вы должны рассмотреть возможность построения вашего приложения Qt асинхронно (с циклом событий), а не пытаться использовать синхронный подход. Таким образом, ваше приложение Qt может делать вещи в параллельный... например, чтение ввода или ожидание ввода от удаленного процесса, пока он еще не заблокирован и может принимать ввод пользователя.
Comments