Я хочу убить / завершить процесс, который я создал при выходе из приложения:
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QPushButton w; w.show();
struct Lambda {
static void run() {
static QProcess p; //version 1
// QProcess& p = *new QProcess(qApp); //version 2
p.connect(qApp, &QApplication::aboutToQuit, &p, &QProcess::kill);
p.connect(qApp, &QApplication::aboutToQuit, &p, &QProcess::terminate);
p.connect(qApp, &QApplication::aboutToQuit, &p, &QProcess::close);
p.connect(qApp, &QApplication::aboutToQuit, &p, &QProcess::deleteLater);
p.start("caffeinate -d");
}
};
QtConcurrent::run(Lambda::run);
return a.exec();
}
С версией 1: мое приложение запускается так, как я ожидаю: создать и уничтожить процесс успешно, но при выходе из приложения QCreator сообщает: «QProcess: уничтожено, пока процесс (« caffeinate ») все еще работает».
С версией 2: мое приложение может запустить процесс, но не может завершить или завершить процесс при выходе, и нет отчетов, как указано выше.
Я просто хочу спросить, почему при создании в куче, QProcess не может быть убит как стационарная версия? Спасибо!
(Я использовал struct Lambda, потому что я не могу использовать C ++ 11 лямбда в моем проекте)
В обоих случаях сигналы не доставляются; в первом случае деструктор убивает процесс, во втором он даже не имеет возможности запустить.
В общем, ваш код представляет собой хороший сборник практически всех бездушных QObject
, QThread
, сигналы и т.п .; читать Потоки и объекты QObject прежде чем делать что-либо с потоками, объектами QObject и сигналами в Qt. Это важная информация, без которой вы будете только делать беспорядок, как это. * Также этот Статья в вики дает хорошее изложение «правильного способа» использовать потоки с Qt.
Давайте назовем основной поток нить А и тема началась QtConcurrent::run
резьба B.
когда run
запускается из второго потока, p
создан, поэтому он имеет родство нитей с резьбой В. По этой причине все connect
Вы выступаете на нем соединения в очереди (по умолчанию для connect
является AutoConnection
, который использует QueuedConnection
если связанные объекты имеют различное сродство потока — и qApp
создан в нить А).
Проблема в том, что соединения в очереди работают, только если в принимающем потоке работает цикл обработки событий (они реализованы как sendEvent
, так что если в целевом потоке нет событий обработки цикла, они только накапливаются в очереди событий), тогда как здесь run
возвращается сразу после запуска процесса.
Так, kill
, terminate
, close
а также deleteLater
никогда не называются. Заметить, что:
deleteLater
в этом случае все равно было бы ошибкой, так как он будет пытаться сделать delete
на static
объект;kill
ни terminate
являются синхронными, поэтому, чтобы убедиться, что процесс мертв, прежде чем продолжить, вам нужно было бы также waitForFinished
;QtConcurrent::run
будет мертвым после run
завершаясь1; это определенно плохо, потому что вы будете иметь QObject
s лежит вокруг с привязанностью нити к нити, которая мертва. Я не знаю, как изящно sendEvent
обрабатывает эту ситуацию.Во всяком случае, когда программа заканчивается, p
деструктор вызывается автоматически как обычная часть завершения работы приложения C ++2; как задокументировано, деструктор QProcess
завершает процесс, с которым он связан, если он все еще работает (но также записывает «страшное сообщение», которое вы видели).
Как и в случае 1, вы создаете QProcess
с резьба B сродство; так что все, что мы сказали выше о событиях не доставляются & сотрудничество. все еще применяется.
Здесь есть три основных различия:
p
в qApp
, который живет в главном потоке; это явно запрещено, все родительско-дочерние отношения между объектами QObject должны существовать между объектами с одинаковой привязкой к потоку; вероятно, вы получаете какое-то предупреждение в консоли об этом факте (setParent
Явно проверяю, живут ли объекты в одном потоке QObject
конструктор делает то же самое);deleteLater
могло бы быть уместным (если бы у вас был цикл обработки событий), так как вы выделяли new
;p
деструктор никогда не вызывается, так как он был наделен new
и никто не звонит delete
в теме; по этой причине запущенный процесс продолжает работать (также у вас небольшая утечка памяти).Итак, что было бы правильным способом справиться с этим? Лично я бы вообще избежал потоков и сигналов. Запуск процесса уже асинхронный, так что вы могли бы просто сделать:
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QProcess p;
p.start("caffeinate -d");
QPushButton w; w.show();
int ret = a.exec();
p.close();
return ret;
}
как всегда с потоками, очередями событий, сигналами и тому подобным: не усложняйте, чем нужно.
На практике в этом случае вы, вероятно, не заметите, потому что QtConcurrent
использует глобальный пул потоков, который убивает закрученные потоки только после 30 секунд простоя.
Общий совет: обычно вы не хотите, чтобы «сложные» объекты уничтожались таким образом, так как main
уже завершено, поэтому (1) это усложняет отладку и (2) если у вас есть объекты Qt, которые зависят от QApplication
еще жив (как правило, все в QtGui и QtWidgets) вы начнете получать странные сбои при завершении программы.