Russian Qt Forum
Ноябрь 23, 2024, 03:09 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Убийство процесса.  (Прочитано 4676 раз)
FreshMeat
Гость
« : Март 13, 2017, 09:46 »

Доброго времени суток!

Возникла следующая проблема: я писал фронтенд с графическим интерфейсом к консольному приложению. Помимо всего прочего, при закрытии он должен был убивать запущенный процесс консольного приложения, которое имеет свойство работать долго и использовать много ресурсов компьютера. Выглядит это так:
  • Есть класс главного окна, в котором в 'closeEvent' перед закрытием посылается сигнал 'Kill()';
  • Есть другой класс, унаследованный от 'QObject', внутри которого происходит вызов консольного приложения через 'QProcess', и объект которого после создания в главном окне помещается в отдельный поток;
  • Есть 'connect', связывающий сигнал главного окна 'Kill()' и слот второго класса 'Kill()' через 'Qt::DirrectConnection'. Проверено лично - после закрытия главного окна слот получает предназначенный ему сигнал - следовательно, главное окно со своей задачей справляется;
  • Во втором классе вызов консольного приложения происходит через функцию, в которую передаётся предварительно сформированная строка 'QString line' из имени и параметров запуска консольного приложения, далее внутри неё создаётся 'QProcess process' и стартует приложение 'process.start(line)', затем начинается цикл, в котором считывается вывод приложения, пока 'process.state()' не равно нулю;
Здесь появляется проблема - в этом же цикле идёт проверка глобальной логической переменной, истинное значение которой означает необходимость завершить программу: 'if(toKill)process.kill()'. Как понятно, в конструкторе класса прописана инициализация этой переменной нулём, а единицей она становится в слоте 'Kill()'. Казалось бы, всё готово для убийства процесса. Ан нет, после закрытия процесс продолжает работать как ни в чём не бывало.
Из всех попыток что-то изменить удалась только одна - поместить во второй класс глобальную переменную типа 'QProcess', в функции вызова вместо создания нового 'QProcess' сразу стартовать строку из глобального, в слот 'Kill()' сразу вызывать 'process.kill()'. Да, консольное приложение в этом случае закрывается, но при каждом новом вызове 'process.start(line)' выводится предупреждение вида:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QProcess(0x5f9698), parent's thread is QThread(0xb037738), current thread is QThread(0xdad7780)

Вопрос - как же всё-таки грамотно реализовать убиение процесса?
« Последнее редактирование: Март 13, 2017, 09:56 от FreshMeat » Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #1 : Март 13, 2017, 09:59 »

Ты некорректно работаешь с процессом. Отдельный поток вообще не нужен. Вешайся на сигнал QProcess::readyReadStandardOutput и в слоте читай данные.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
FreshMeat
Гость
« Ответ #2 : Март 13, 2017, 14:28 »

Цитировать
Ты некорректно работаешь с процессом. Отдельный поток вообще не нужен.
Я его и не создаю, вроде как. Вот код той функции.
Код:
void MyClass::Run(QString line)
{
    process.setReadChannel(QProcess::StandardError);
    process.start(line);
    do
    {
        process.waitForReadyRead(-1);
        emit SendOut(process.readAllStandardError());
    }
    while(process.state());
}
Спросите, зачем wait? Просто мне необходимо дожидаться завершения работы.
Цитировать
Вешайся на сигнал QProcess::readyReadStandardOutput и в слоте читай данные.
Звучит как хорошая идея, но тогда как добиться ожидания конца работы? Через QEventLoop?
Записан
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #3 : Март 13, 2017, 14:35 »

Звучит как хорошая идея, но тогда как добиться ожидания конца работы? Через QEventLoop?

при окончании работы qprocess выкинет сигнал
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #4 : Март 13, 2017, 14:38 »

FreshMeat, используй асинхронную работу с QProcess через сигналы/слоты.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
FreshMeat
Гость
« Ответ #5 : Март 13, 2017, 16:39 »

при окончании работы qprocess выкинет сигнал
Который сам по себе не тормозит выполнение остальной части кода. Или я не прав?

FreshMeat, используй асинхронную работу с QProcess через сигналы/слоты.
Уже пытаюсь организовать. Читая документацию Qt, узнал, что сигналы с сигналами можно коннектить, что упростило часть задачи. Теперь вот гадаю, как законнектить сигнал процесса на готовность чтения с сигналом второго класса на отправку строки вида 'SendLine(QString)', ведь нужно как-то указать, что отправить нужно именно содержимое выходного канала, а не просто QString.
Грубо говоря, на ум сразу напрашивается нечто подобное:
Код:
connect(&process,SIGNAL(readyReadStandartError()),this,SIGNAL(SendLine(QString)));
но так, чтобы в 'QString' попал 'process.readAllStandartError()'.
« Последнее редактирование: Март 13, 2017, 17:04 от FreshMeat » Записан
FreshMeat
Гость
« Ответ #6 : Март 13, 2017, 17:30 »

В общем, соединив сигнал главного окна 'Kill()' с сигналом второго класса 'Kill()', а тот в свою очередь со слотом процесса 'kill()', я добился того, чего хотел - процесс теперь исправно закрывается с закрытием главного окна. Всем спасибо, все свободны.

Напоследок уточню - удалив первый пост, я удалю только его или всю тему?
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #7 : Март 14, 2017, 07:54 »

Не удаляй, вдруг, кому-то еще понадобится. А по поводу сигнала, сделай промежуточный слот, в котором вычитаешь данные и заэммитишь сигнал с ними.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
FreshMeat
Гость
« Ответ #8 : Март 14, 2017, 09:16 »

Не удаляй, вдруг, кому-то еще понадобится.
Хорошо, не буду.
Цитировать
А по поводу сигнала, сделай промежуточный слот, в котором вычитаешь данные и заэммитишь сигнал с ними.
Я сделал бы, если бы знал, как правильно взаимодействовать с 'sender()'-ом, ибо сигнал 'readyRead()' сам по себе ничего не отправляет. Его, наверное, можно было бы перегрузить ручками, но зачем, если циклическое чтение полностью удовлетворяет мои требования для данной задачи? Тут просто суть в том, что мне не нужна асинхронная работа процесса и объекта класса, его вызывающего, они должны выполняться по очереди, друг за другом. А раз так, к чему организовывать слот-сигнальные взаимодействия процесса и класса по отслеживанию завершения, готовности, когда можно просто пустить их в одном потоке, но отдельном от главного окна?
Впрочем, послушаю любой совет, как это дело облагородить.
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #9 : Март 14, 2017, 13:00 »

Отдельный поток тебе не нужен, я уже говорил об этом. Смотри пример. Создай класс ProcessCommunicator, в котором инкапсулируй QProcess, а наружу прокинь сигнал newLineAvailable(const QString &line). Это как вариант.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.051 секунд. Запросов: 22.