Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Assert failure: cannot send event to object owned by other thread; Debug only error in msvc using qthreadpool and qrunnable

Assert failure: cannot send event to object owned by other thread; Debug only error in msvc using qthreadpool and qrunnable

Scheduled Pinned Locked Moved Unsolved General and Desktop
4 Posts 2 Posters 729 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    michael9142
    wrote on last edited by michael9142
    #1

    hello dear qt people,

    currently i am facing a problem with my msvc17 x64 compiler in debug mode with my qt gui application (qt version 5.12.2 on win10, c++17).

    i am using an qtimer (in QWidgetClassInMainThread class) to call every ~20 to 50ms the method QWidgetClassInMainThread::startImageProcessingIteration().
    that method should create an qrunnable derived object getting passed an opencv mat image in the constructor.

    this qrunnable will be passed later to an qthreadpool to do some calculations and drawings on the opencv image.
    in the end the opencv image will be converted to an qimage in the reimplemented run() and an signal should emit the qimage back to the main thread where the qimage will be shown in gui (it is possible that further emits in run() have to be implemented later).

    because of the frequent call of the method by the qtimer and the need to start threads again and again, i decided to use the threadpool.

    unfortunately while running the application in debug mode the program crashes on start with the error message:

    ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread ...
    

    the strange thing is that when starting the program in release mode it runs without any problems and errors.

    i tried to change the setAutoDelete() value of the qrunnable in QWidgetClassInMainThread::startImageProcessingIteration(), with more or less success (see comment in code).

    now i am a bit clueless and hope any qt pros can give me some tips or suggestions ;) thank you guys!

    Code (shortened):

    QWidgetClassInMainThread.hpp

    class QWidgetClassInMainThread : public QWidget
    {
        Q_OBJECT
    
    private:
        QLabel label{this};
        QPixmap pixmap{};
    
        QTimer imageTimer{this};
    
        QThreadPool threadpool{this};
    
        void startImageProcessingIteration();
    
        void setImageInQLabel(QImage);
    
    public:
        QWidgetClassInMainThread(QWidget *parent = nullptr);
    };
    

    QWidgetClassInMainThread.cpp

    Q_DECLARE_METATYPE(QImage);
    
    QWidgetClassInMainThread::QWidgetClassInMainThread(QWidget *parent)
        : QWidget(parent)
    {
        qRegisterMetaType<QImage>();
    
        // connect qtimer to startImageProcessingIteration()
        connect(&imageTimer, &QTimer::timeout, this, &QWidgetClassInMainThread::startImageProcessingIteration);
    }
    
    // method called every ~20ms to ~50ms by qtimer
    void QWidgetClassInMainThread::startImageProcessingIteration()
    {
        // create new qrunnable and pass cloned opencv mat image, from camera object, in constructor
        auto *iteration = new CalculationRunnable(this, camera.getCurrentOpenCVImage());
    
        // connect emit from iteration object with setImageInQLabel()
        connect(iteration, &CalculationRunnable::sendImageToMainThread, this, &QWidgetClassInMainThread::setImageInQLabel);
    
        // VARIANT 1
        iteration->setAutoDelete(true); // error with msvc in debug mode, AND ONLY in debug mode! -> assert failure ... cannot send event to object owned by other thread ...
        // VARIANT 2
        iteration->setAutoDelete(false); // no errors but what todo with the iteration pointer variable because it will not be deleted by the threadpool?
    
        // put qrunnable in threadpool
        threadpool.start(iteration);
    }
    
    void QWidgetClassInMainThread::setImageInQLabel(QImage qImage)
    {
        // update qpixmap and qlabel in main thread
        pixmap.convertFromImage(qImage);
        label.setPixmap(_pix);
    }
    

    CalculationRunnable.hpp

    class CalculationRunnable : public QObject, public QRunnable
    {
        Q_OBJECT
    
    private:
        cv::Mat openCVImage;
    
    public:
        CalculationRunnable(QObject *parent, cv::Mat openCVImage);
    
    public:
        void run() override;
    
    signals:
        void sendImageToMainThread(QImage);
    };
    

    CalculationRunnable.cpp

    CalculationRunnable::CalculationRunnable(QObject *parent, cv::Mat openCVImage)
        : QObject (parent)
        , QRunnable ()
        , openCVImage(openCVImage)
    {}
    
    void CalculationRunnable::run()
    {
        auto image = openCVImage;
    
        /*
         * Do something with cv image.
         * do other emits.
         */
    
        // convert OpenCV image to QImage
        QImage qimage = cvMatToQImage(image);
    
        // send signal with qimage to main thread to update qpixmap/qlabel
        emit sendImageToMainThread(qimage);
    }
    
    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi and welcome to devnet,

      Since you make it deletable, don't pass a parent to it.

      One other thing, for all QObject based variables that you keep on stack, don't set the parent. This will trigger a double delete. Once because to the parent/child relationship and once because of the destruction happening when going out of scope.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      3
      • M Offline
        M Offline
        michael9142
        wrote on last edited by
        #3

        thanks for your reply and sorry for long time to answer.

        so you suggest to create the qrunnable that way:

        // no this in ctor
        auto *iteration = new CalculationRunnable(nullptr, camera.getCurrentOpenCVImage());
        
        ...
        
        iteration->setAutoDelete(true);
        threadpool.start(iteration);
        

        and about your second recommendation, do you mean i should not pass this in the class variables:

        class QWidgetClassInMainThread : public QWidget
        {
         ...
            QTimer imageTimer{}; // no this
        
            QThreadPool threadpool{}; // no this
        ...
        
        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Class members are "local" variable so they will get destroy on instance destruction. If you give a parent to these objects, then they will also be part of the child tree of the widget and deletion will also be triggered on them.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          2

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved