Как использовать процесс (QProcess) в новом потоке (QThread)?

У меня есть следующий код:

 void Processmethod()
{

    QDialog *ProcessMessage = new QDialog;      
    Ui::DialogProcessMessage Dialog;            
    Dialog.setupUi(ProcessMessage);             
    ProcessMessage->setModal(true);
    ProcessMessage->setAttribute(Qt::WA_DeleteOnClose); 
    ProcessMessage->show();

    qApp->processEvents();

    processmethodONE();  
    processmethodTWO();
    processmethodTHREE();                  
}

void processmethodONE()
{
    QString ProcessCommand = "w8 " + blablubli";            

    Prozess.setWorkingDirectory(Path);         //QProcess "Prozess" is globaly defined  
    Prozess.setStandardOutputFile(Path);       //in my class

    QThread* thread = new QThread;
    Prozess.moveToThread(thread);
    Prozess.start(ProcessCommand);


while(!Prozess.waitForFinished(2000))
   {
       std::cerr << "Process running " << std::endl;
   }

QProcess::ExitStatus Status = Prozess.exitStatus(); 

if (Status == 0)
 {
   std::cout << "File created!" << std::endl;
 }
}

В этом исходном коде я пытаюсь открыть всплывающее диалоговое окно перед запуском некоторых процессов. проблема в том, что диалоговое окно не кликабельно, но в диалоговом окне я хочу создать кнопку, чтобы прервать текущий метод. Как видите, я пытался использовать QThread для запуска процессов в другом потоке, но все равно не могу щелкнуть диалоговое окно. Кроме того, если я открою свое приложение (графический интерфейс) с помощью файла «application/x-executable», содержимое диалогов отсутствует при активации показанного выше метода. Как я могу исправить эти проблемы? Где я не прав? Привет


person Streight    schedule 25.03.2012    source источник
comment
У меня есть несколько вопросов... 1) Как вы звоните Processmethod()? 2) Почему вы считаете, что вам нужно создать QThread и переместить в него QProcess? И еще, почему вы тогда не запускаете новый QThread? 3) Вы используете этот глобальный QProcess для всех ваших processmethodX()?   -  person jdi    schedule 25.03.2012
comment
это не соответствует вопросу, но я предлагаю вам писать имена переменных в lowerCamelCase. Это очень быстро читается. Однако я согласен с jdi, нужно больше информации, чтобы ответить.   -  person jalone    schedule 25.03.2012
comment
Обычно нет необходимости запускать QProcess в потоке, поскольку его API не блокируется, если только вы не используете методы waitForStarted/Finished.   -  person Frank Osterfeld    schedule 25.03.2012
comment
@FrankOsterfeld: Держу пари, что как только ОП даст нам ответы на мои вопросы, станет ясно, что здесь есть лишняя ерунда (вы правы, не нуждаясь в QProcess в потоке)   -  person jdi    schedule 25.03.2012
comment
1) Я вызываю Processmethod() при нажатии кнопки. 2) Я думал, что запуск процесса в другом потоке оставит диалог доступным. Вы правы, я не запустил QThread - моя вина - я должен создать метод подключения и подключить поток к методу, в котором я определяю процесс? 3. У меня есть один QProcess для каждого процесса - не лучше ли снова использовать точно такой же? Прошу прощения за свою ошибку, но у меня были проблемы с пониманием методов QThread, вероятно, из-за того, что мой английский недостаточно хорош. @Frank: Как вы видите, я использую waitForFinished - отредактировал свой вопрос.   -  person Streight    schedule 25.03.2012
comment
Да, вы должны использовать отдельные экземпляры QProcess, так что это нормально. QThread позволит вашему диалогу продолжать работать, как и QProcess, но только если вы не пойдете и не заблокируете свой основной поток, ожидая их завершения. Выберите один или другой: QThread или QProcess, и используйте их сигналы, чтобы сообщить вашему основному потоку, когда они будут выполнены. Смотрите оба ответа, которые мы дали   -  person jdi    schedule 25.03.2012
comment
Проблема в том, что я хочу, чтобы основной поток (главное окно GUI) зависал, пока процессы запущены, просто всплывающее диалоговое окно должно быть кликабельным. Итак, кто-нибудь знает, как этого добиться?   -  person Streight    schedule 26.03.2012


Ответы (2)


void processmethodONE()
{
   QThread* thread = new QThread;
   Prozess.moveToThread(thread);
   Prozess.start(ProcessComand);

Здесь вы переместили QProcess в другой поток. Но затем вы вызываете для него start(). Это уже не потокобезопасно.

while(!Prozess.waitForFinished(2000))
{
   std::cerr << "Process running " << std::endl;
}

Это блокирует и делает использование потока бесполезным. Кроме того, это не потокобезопасно.

Вместо этого вы должны не использовать потоки, а:

  1. удалить вызов waitForFinished()
  2. Соедините сигналы Finish() и error() QProcess со слотами, которые затем запускают следующий шаг, т.е. processMethodTWO.

Я бы также посоветовал не использовать повторно объекты QProcess и просто создавать новый для каждого шага.

person Frank Osterfeld    schedule 25.03.2012
comment
Хорошо, я сначала попробую это. У меня уже есть для каждого процесса один отдельный объект QProcess — вот что я хотел сказать своим первым комментарием. - person Streight; 25.03.2012
comment
Теперь я попытался соединить сигнал finish() первого процесса Prozess со вторым методом processmethodTWO() с помощью connect(Prozess, SIGNAL(finished()),processmethodTWO(),(SLOT(start()))); , но я получаю сообщение об ошибке: недопустимое использование выражения void. -› наверное нуб фейл :). - person Streight; 25.03.2012
comment
Использование сигнала finished() вместо блокировки waitForFinished() действительно помогло. Сторона QML буферизировала все испускаемые сигналы, из-за чего пользовательский интерфейс не отвечал до тех пор, пока QProcess не будет окончательно завершен. Большое спасибо за простой, но спасительный пост, который все еще актуален спустя десятилетие :) - person Nazım Gediz Aydındoğmuş; 18.01.2021

Хотя я до сих пор не до конца понимаю ваш недавно обновленный пример кода, я чувствую, что это может быть вашей проблемой:

while(!Prozess.waitForFinished(2000))
   {
       std::cerr << "Process running " << std::endl;
   }

Везде, где вы действительно вызываете это в своем исходном коде, происходит блокировка в ожидании завершения Prozess.

Используйте новый экземпляр QProcess для каждого из них и соедините их сигналы finished(). на СЛОТ, который будет вызван, когда они закончат. Не опрашивайте их вручную и не блокируйте. Это позволит вам полностью избавиться от QThreads.

person jdi    schedule 25.03.2012
comment
У меня есть один глобальный для каждого процесса, это означает one QProcess Prozess for processmethodONE(); , one QProcess Prozess2 for processmethodTWO();... Метод waitForFinished() мне нужен, потому что процессам нужно некоторое время, а предыдущий процесс всегда должен быть завершен до запуска следующего. - person Streight; 25.03.2012
comment
Если это так, то вы должны сделать другой подход. В вашем примере предполагается, что все процессы могут работать одновременно. Если вам нужно, чтобы они запускались по порядку, вы можете связать сигнал finished() одного с слотом start() следующего и так далее. - person jdi; 25.03.2012
comment
Или вы можете просто создать один пользовательский QThread, который выполняет все ваши команды, используя синхронные системные вызовы нижнего уровня C++, поскольку QProcess больше не является преимуществом. А затем просто используйте сигнал QThread finish(), чтобы объявить, что все сделано. - person jdi; 25.03.2012
comment
Сейчас я попытался связать сигнал Finish() первого процесса Prozess со вторым методом processmethodTWO() с connect(Prozess, SIGNAL(finished()),processmethodTWO(),(SLOT(start()))); , но получаю сообщение об ошибке недопустимое использование выражения void. -› наверное нуб фейл :). - person Streight; 25.03.2012
comment
да, нуб не справился :-) Делай SLOT(Procezz2.start()), а не processmethodTWO(). То, что вы делаете, пытается вызвать это. Честно говоря, я даже не уверен, что этот синтаксис правильный. я питон парень - person jdi; 25.03.2012
comment
я повторил попытку с connect(Prozess, SIGNAL(finished()), this,(SLOT(processmethodTWO.start()))); , но теперь получаю ошибки Error: no matching function for call to 'GUI :: connect (qprocess &, const char *, const GUI *, const char *) " и Candidates are: / usr/include/qt4/QtCore/qobject.h: 198:17: note: static bool QObject :: connect (const QObject *, const char *, const QObject *, const char *, Qt :: Connection Type)............ - person Streight; 25.03.2012
comment
РЖУ НЕ МОГУ. Извините, я парень на питоне. Скорее всего: connect(Prozess, SIGNAL(finished()), Prozess2, SLOT(start())) - person jdi; 25.03.2012
comment
Не работает. Кроме того, Prozess2 полностью определен локально только в processmethodTWO() (см. processmethodONE() в моем вопросе), поэтому прямой вызов Prozess2.start не сработает. Если бы это сработало, мне пришлось бы вызвать метод processmethodTWO(). - person Streight; 26.03.2012
comment
По сути, мой ответ изложил, что вам нужно сделать. Это все просто организационные вопросы вашего кода. Мое предложение само по себе твердое. Я не могу переписать весь ваш код за вас. - person jdi; 26.03.2012
comment
Да, верно, также спасибо за ответ, но Фрэнк Остерфельд сначала дал тот же ответ, поэтому мне придется принять его ответ. однако, спасибо :). - person Streight; 26.03.2012
comment
Смешной. Ну, на самом деле я опубликовал первый ответ, а он немного позже. Но что угодно! Удачи! - person jdi; 26.03.2012