Search code examples
c++multithreadingqtqtcoreqt-signals

Qt signal slot over thread, is this the safe way?


Say, I have 2 threads: A and B, A is the main thread. In thread A, there are two on_button_click slots. The first one is:

on_button_one_clicked(){
  myObject_one = new myObject(this);
  myObject_one->setParent(map);
  myObject_two = new myObject(this);
  myObject_two->setParent(map);
  ...
}

The second one is:

on_button_two_clicked(){
  foreach(myObject* i, map->childItems){
    delete i;
  }
}

Here, myObject and map are all QGraphicsItems. In thread B, a signal is emitted to trigger a slot of thread A:

slot_triggered_by_signal_from_thread_B(){
  foreach(myObject* i, map->childItems){
    i->do_some_thing();
  }
}

Is this safe? Will it happen, when the codes comes to the line i->do_some_thing and meet an empty pointer and crash?


Solution

  • It is safe as long as you use the auto connection or queued conncetion type between the threads since then the slot will be only invoked when your other slot is finishing up or vice versa. They will not be running "simultaneously". That is the only concern that I could imagine for this not to be safe enough. I believe you meant a scenario like this:

    main.cpp

    #include <QThread>
    #include <QApplication>
    #include <QTimer>
    #include <QObject>
    #include <QPushButton>
    #include <QDebug>
    
    class Work : public QObject
    {
        Q_OBJECT
        public:
            explicit Work(QObject *parent = Q_NULLPTR) : QObject(parent) { QTimer::singleShot(200, this, SLOT(mySlot())); }
        public slots:
            void mySlot() { emit mySignal(); }
        signals:
            void mySignal();
    };
    
    class MyApplication : public QApplication
    {
        Q_OBJECT
        public:
    
        explicit MyApplication(int argc, char **argv)
            : QApplication(argc, argv)
            , pushButton(new QPushButton())
        {
            QStringList stringList{"foo", "bar", "baz"};
            QThread *workerThread = new QThread();
    
            Work *work = new Work();
            work->moveToThread(workerThread);
    
            connect(pushButton, &QPushButton::clicked, [&stringList] () {
                for (int i = 0; i < stringList.size(); ++i)
                    stringList.removeAt(i);
            });
            connect(work, &Work::mySignal, [&stringList] () {
                for (int i = 0; i < stringList.size(); ++i)
                    qDebug() << stringList.at(i);           
            });
        }
    
        ~MyApplication()
        {
            delete pushButton;
        }
    
        QPushButton *pushButton;
    };
    
    #include "main.moc"
    
    int main(int argc, char **argv)
    {
        MyApplication application(argc, argv);   
        return application.exec();
    }
    

    main.pro

    TEMPLATE = app
    TARGET = main
    QT += widgets
    CONFIG += c++11
    SOURCES += main.cpp
    

    Build and Run

    qmake && make && ./main