Starting QProcess inside a thread
-
I have been struggling with this basic problem for a while now.
I’m trying to start a QProcess from a thread. Starting the process works and the process runs correctly but my problem is that the finished() signal is never emitted.Here is my example:
My class variables are
std::atomic<bool> recording; QProcess proc; std::unique_ptr<std::thread> recordingThread;
The class:
Recorder::Recorder(ParentClass *parent): QObject(parent){ connect(&proc,SIGNAL(finished(int)),this,SLOT(finishedFFMPEG())); } void Recorder::start(){ if (!recordingThread){ recording = true; recordingThread.reset(new std::thread(&Recorder::recordThread, this)); } } void Recorder::recordThread(){ while(recording){ //writing frame } proc.start("C:\\ffmpeg.exe", QStringList() <<"-i"<< picDir.c_str() << "-r"<< "30" << "-vcodec"<< "ffv1" << filename.c_str()); proc.waitForStarted(); } void Recorder::stop(){ if (recordingThread) { recording = false; recordingThread->join(); recordingThread.reset(); } } void Recorder::finishedFFMPEG(){ qDebug() << "finished"; }
start() and stop() are called from another non-GUI thread in my ParentClass.
I tried everything from using pointers, running my recordThread() as a QThread and starting the QProcess in the stop() function but I simply never receive the finished() signal from the process. The process itself is being executed correctly. I know the problem lies in the different event loops.
How can I achieve my goal of starting a process after the recordThread() finishes and catching the QProcess finished() signal?
-
It looks like there's no use of an event loop in the thread that starts the process. Without this or the use of a function that blocks until the process terminates, process termination won't be detected. In general, Qt's asynchronous interfaces depend on the event loop or triggering via a synchronous (relatively speaking) interface.
-
I know it has to do with the event loop but I can't find a way to make it work. I can't just block recordThread() until the process is finished because I need a new recordThread() to be able to start while the process is still running. Do you have any suggestion how I can achieve my goal?
-
Hi,
Since you are using Qt why not use a QThread ? But first thing, are you sure you need a thread at all to call QProcess ?
-
I'm not sure if you read the main post as I stated that I did try running it as a QThread. The QProcess has to run after the recordThread() finishes its task.
-
Presuming that the thread structure in use is appropriate, and the presence of a main thread running QCoreApplication::exec(), you can move the QProcess object to the main thread with QObject::moveToThread.
void Thread::run() { QProcess *process = new QProcess(); connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(done())); process->start(program, QStringList()); if (!process->waitForStarted()) qDebug() << "error"; else process->moveToThread(QCoreApplication::instance()->thread()); } void Thread::done() { qDebug() << "process done"; }
Another option is to use a QObject previously associated with the main thread with a slot that starts the external process.
-
Yes, I did read it but misinterpreted your use of QThread.
You should rather split responsibilities here. Have your recording thread do only that: recording. And once it's done make it emit a signal that you will connect to a slot that will start the ffmpeg QProcess. That way you can also encapsulate ffmpeg so that you can retrieve its output to check that everything is going fine.