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?


  • Lifetime Qt Champion

    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.


  • Lifetime Qt Champion

    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.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.