QT QProcess memory management - qt

If I use this in my program to start a ffmpeg command.
QProcess *cmd1 = new QProcess();
cmd1->start(ffmpeg command);
if (!cmd1->waitForStarted())
return false;
if (!cmd1->waitForFinished())
return false;
then on finishing process will memory be deallocated of its own from heap or I have to use
delete cmd1.

Alternatively, or in addition you can set the process to delete itself when it is finished: -
// using Qt 5 connect syntax
connect(cmd1, &QProcess::finished, cmd1, &QProcess::deleteLater);
This is probably the preferred method, if the parent object that you pass to your QProcess object is likely to have a much longer lifetime than the QProcess object requires.

If you set Parent to QProcess like below, then you dont need to delete it manually.
Parent can be the QObject who is creating the QProcess.
QProcess *cmd1 = new QProcess(parent);
But if you can not set parent then you need to delete it.

Related

How to read QProcess output

In the main thread of a Gui Application I am starting a QProcess of another GUI application that will log some messages over time in stdout using fputs(). The problem is that after some time the GUI application started with QProcess will freeze because it's output is not consumed by the parent. I know that this is the problem because if I am starting the QProcess with QIODevice::NotOpen or QIODevice::Unbuffered argument, it will not get stuck but the output will never be reached.
I've tried to connect the readyRead, readyReadStandardError, readyReadStandardOutput signals of the subprocess to a slot in the parent, but for some reasons the signals are never emitted. I am also flushing the stdout after each write.
My question is how to force QProcess to send some data in real time without closing it?
The connection of the signals, (T- is a wrapper for QProcess):
process->setWorkingDirectory(workingDir);
process->start(prog, argumentsList);
process->waitForStarted();
T* reciver = new V8QProcess(process);
QObject::connect(process, &QProcess::readyRead, reciver, &V8QProcess::OnMessageRecieved);
QObject::connect(process, &QProcess::readyReadStandardError, reciver, &V8QProcess::OnMessageRecieved);
QObject::connect(process, &QProcess::readyReadStandardOutput, reciver, &V8QProcess::OnMessageRecieved);
The code of the subprocess that will log in stdout:
QByteArray bytes = LogMsg::getDisplayable(logMsg, 0).toUtf8();
fputs(bytes.constData(), stdout);
fflush(stdout);
The code of the OnMessageRecieved:
if (!p) { // p is the QProcess
return;
}
QByteArray output;
output.append(p->readAllStandardError()).append(p->readAll());
QString message = QString::fromStdString(output.toStdString());
This approach is working when running a shell script or other simple program.
I found out what the problem was on my case:
Because I was starting the QProcess in a std::Thread, the events(signals) that occur were skipped because std::Thread don't have a queue of events as QThread or QApplication does.
The solution that I use is:
1. Use QThread instead of std::thread
2. Call QCoreApplication::proccesEvents() from time to time.
The proper solution is to use QThread::exec() in order to create an event loop, but this approach would block the GUI Application, so in my case is no good.

QProcess state() always returns RUNNING

I do the following to start a process and waits for its completion (I am intentionally avoiding use of SIGNAL/SLOTS in this case).
QProcess *myProcess = new QProcess();
QString program = "test.exe";
QStringList args;
myProcess->start(program, args);
myProcess->waitForStarted();
while( myProcess->state() == QProcess::Running )
{
// Do other things...
}
I can verify that test.exe exits. But process state is for some reason always QProcess::Running. I am using Qt 4.8.2 on Windows.
If "do other things" does not include processing events of the thread's event loop, then the QProcess never gets a chance to update its state.
Either waitForFinished if this needs to block the thread or connect to the finished() signal.
I don't think state() should be used to check for a program that has closed down but you can use something like while(!waitForFinished(1)).

QThread and QML Locking Up

I have a class, audio_engine_interface, and in main.cpp, I add it to the QML thing.
viewer.rootContext()->setContextProperty("engine", engine);
In audio_engine_interface, I have a audio_engine class, which is computationally intensive—it needs to run on its own thread.
void audio_engine_interface::play()
{
QThread thread;
thread.start();
engine->moveToThread(&thread);
engine->play(); // Will use 100% of CPU
}
However, when I do this, the whole QML thread locks up, meaning I can't pause (pretty important). Am I missing something?
EDIT:
This thread won't mess up anything or access objects from other places. However, it does have a pause function that will need to be called at some point. For what it's worth, the engine is doing pitch shifting.
This is a problem: -
Qthread thread;
Creating a QThread object like this is creating it on the stack. When the function ends, the object will go out of scope and delete the QThread object.
You need to dynamically allocate the object on the heap: -
QThread* thread = new QThread;
Then remember to delete the thread, or set it to delete itself: -
//Qt 5 connect syntax
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
You should also be aware of thread affinity (the thread which an object is running on). I suggest reading this article on how to use QThread properly.
You have so many problems.
when you move to thread your object must not have a parent
your thread object is local variable so it will day immediately when udio_engine_interface::play() end execution
you are invoking you engine->play(); method directly and this means that it will be executed in current thread.
moveToThread means that slots invked by signals connected using default 5th parameter (Qt::AutoConnection) will be queued in event loop of given thread.
The easiest way to fix it is use QtConcurrent:
void audio_engine_interface::play()
{
QtConcurrent::run(engine, &EngineClass::play);
}
Depending what your engine does you should make it thread safe (use mutex locks an so on), without details it is hard to tell, what exactly you should do.

Auto Updater Examples

Well i've been looking how to do an auto updater on google, however no success.
What i would plan is to create an updater (ANother exe called by QProcess though the principal exe) but here ihave some questions:
How do i make the QProcess silent?
If there's a new version, how do i show a notification on the window from where the process has been started (I meant i've create the process in Game.exe, i want to send a notification to Game.exe from Updater.exe that there's a new version available.)
Thanks for the answers.
First, I've never encountered a need to create anything other than a QThread to handle my update needs. The QProcess would be helpful if, once the user updates, you want to download, install, and relaunch the program while the user continues with the main program. (But this can all be achieved with a shell script, python script, even BAT file)
When you use QProcess, you will have to rely on the signals readyReadStandardError() and readyReadStandardOutput(). Then the application that your process is calling should send its output to stderr or stdout. Updater.exe should write to either of these files.
I would imagine your Updater to make use of QNetworkAccessManager::finished(QNetworkReply *reply). When this slot is called, please do something nicer than this:
void Updater::replyFinished(QNetworkReply *reply){
QString r(reply->readAll());
if(r.contains(SERVER_REPLY_UPDATE_AVAILABLE)){
qDebug() << "yes";
}else{
qDebug() << "no";
QApplication::quit();
}
}
If Updater.exe is going to be a full blown GUI application, do not call the show() method unless it's needed and it should appear to run in the background. I would prefer a script, but you know me.
Then your Game.exe will set up a QProcess. You can pass arguments to the process within the QProcess::start() function.
Good arguments that will help direct your update process would be:
Game.exe version number
"check_for_updates"
"ignore_updates"
"download_update"
finally, in Game.exe:
...
connect(process,SIGNAL(readyReadStandardError()),this,SLOT(readProcessReply()));
...
void Game::readProcessReply(){
QString r(process->readAllStandardError());
if(r.contains("yes")){
//show your dialog here
}else{
//do nothing
}
}

QProcess.startDetached() and write to its stdin

What is wrong with this code? I can not write to stdin of new process that has been detached.
It is important for me that the new process is detached.
QProcess commandLine;
commandLine.setWorkingDirectory("E:\\"); //does not work.
commandLine.startDetached("cmd.exe"); //works (but uses wrong working dir).
commandLine.write("echo hi\0"); //writes nothing.
commandLine.write("\n\r"); //Still nothing is written!
Good morning.
The problem is that QProcess::startDetached() is a static method which creates a "fire and forget" process.
This means, that you cannot set a working directory this way. All you can do is call
QProcess::startDetached (const QString &program, const QStringList &arguments, const QString &workingDirectory);
This however leaves you with the problem of writing to the stdin of the newly created process. The thing is, since you don't have a QProcess object there is nothing you can write your stdin to. There could be a solution using the process handle the static startDetached() method's providing.
We had the similar problem in our company. We needed detached processes which ran beyond the lifespan of the calling programm and for which we could set the environment. This seemed, looking at the Qt code, impossible.
My solution was to use a wrapper around QProcess with its own startDetached() method.
What it did, it actually created this QProcess subclass on the heap and used its ordinary start() method. In this mode however the signal, which fires once the process has finished, calles upon a slot which deletes the object itself: delete this;. It works. The process is running independently and we can set an environment.
So basically there is no need to use the detached start method. You can use the ordinary start method as long as your QProcess is an object on the heap. And if you care for memory leaks in this scenario you'd have to provide a similar mechanism as described above.
Best regards
D
call static method with arguments doesn't provide any set of process into child command.
process.startDetached(command)
try this:
QProcess process;
process.setProgram(fileName);
process.setArgument(argsList);
process.setWorkingDirectory(dirName);
process.startDetached();

Resources