c++qtopencvqtconcurrentqmutex

QMutex with QConcurrent::run not working as expected?


I am making a Qt GUI application that uses a custom QLabel class (name as ImageInteraction) to show images from a streaming camera while also allowing mouse interaction on the image. As the GUI has other functionalities, the customized QLabel class does the job of extracting the image from the camera and updating its shown image through a while loop in a function which is run in another thread. The code for that is as below:

void ImageInteraction::startVideo()
{
    if (!capture.open(streamUrl))
    {
        QMessageBox::warning(this, "Error", "No input device availabe!");
    }
    else
    {
        QFuture<void> multiprocess = QtConcurrent::run(this, &ImageInteraction::loadVideo);
    }
}

void ImageInteraction::loadVideo()
{
    while(loopContinue){
    cv::Mat frame;
    capture.read(frame);
    if(!frame.empty())
    {
        cv::cvtColor(frame, frame, CV_BGR2RGBA);
        cv::resize(frame, frame, cv::Size(this->width(), this->height()), 0, 0);
        QImage image(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGBA8888);
                this->setPixmap(QPixmap::fromImage(image));
            }
    }
    capture.release();
 }

Here capture is of type cv::VideoCapture and loopContinue is a boolean type which is initially set to be true. There is a closeEvent() function that invokes the method for stopping the capture of the image from the camera.

void MainWindow::closeEvent(QCloseEvent *event)
{
    liveVideo->stopVideoThread();//liveVideo is a pointer to an object of ImageInteraction
    event->accept();
}

where stopVideoThread simply sets the boolean flag loopContinue to false and has the following simple code:

void ImageInteraction::stopVideoThread()
{
    mutex.lock();//QMutex mutex;
    loopContinue = false;
    mutex.unlock();
}

In my understanding the while loop in loadVideo method should be stopped once stopVideoThread method is invoked and loopContinue is set to false. But in reality, when the close button is pressed, apparently it doesn't stop while loop and the application crashes with a message:

The inferior stopped because it received a signal from the operating system.

Signal name : SIGSEGV
Signal meaning : Segmentation fault

Am I using QtConcurrent::run method and the QMutex object erroneously? Could you identify what the problem is? FYI, the OS is ubuntu 14.04 and IDE is QtCreator.

Thanks!


Solution

  • The following is just an idea of the improvements mentioned in the above comments.

    class ImageInteraction
    {
    public:
        ~ImageInteraction()
        {
            multiprocess_.waitForFinished();
        }
    
        void startVideo()
        {
            if (!capture.open(streamUrl))
            {
                QMessageBox::warning(this, "Error", "No input device availabe!");
            }
            else
            {
                multiprocess_ = QtConcurrent::run(this, &ImageInteraction::loadVideo);
            }
        }
    
        void loadVideo()
        {
            while(loopContinue_)
            {
                cv::Mat frame;
                capture.read(frame);
                if(!frame.empty())
                {
                    cv::cvtColor(frame, frame, CV_BGR2RGBA);
                    cv::resize(frame, frame, cv::Size(this->width(), this->height()), 0, 0);
                    QImage image(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGBA8888);
                    this->setPixmap(QPixmap::fromImage(image));
                }
            }
            capture.release();
        }
    
        void stopVideoThread()
        {
            loopContinue_ = false;
            //multiprocess_.waitForFinished(); // you can call this here if you want to make sure that the thread has finished before returning
        }
    
    private:
        QFuture<void> multiprocess_;
        std::atomic<bool> loopContinue_;
    };