简体   繁体   中英

Thread safety of calling QObject's method from another (non-qt) thread?

I have two objects which lives in different threads and I'm trying to figure if a pattern used is thread safe or not.

The first object is QObject-derived and lives (was created in) the main Qt thread. The class contains some Q_INVOKABLE methods that should be called from QML, some signal*() methods defined as signals: and some Emit*() (normal) methods that I use as wrappers to emit signals. For example:

void MyQObjectClass::EmitStatus(void) {
    emit signalStatusChange(_status);
}

I normally listen for those signals in QML.

The second object is not QObject-derived and lives in a second thread ( pthread ). This thread runs its own event loop (libev) and dispatches events. I can't use anything related to Qt in this thread because I need the custom libev event loop. On this object I defined some Notify*() methods that will send async events through libev to be picked up by callbacks.

I need to be able to communicate between the two objects/threads, but I'm not sure how to safely do this.

The actual design is to let the pthread thread object call the different Emit*() methods directly so that the QObject can properly propagate the information to Qt/QML. If I need to send information from Qt/QML to the pthread / libev object I call (from the Qt thread) the Notify*() methods.

When reading Accessing QObject Subclasses from Other Threads , it says:

QObject and all of its subclasses are not thread-safe. This includes the entire event delivery system.

but then further it is stated that:

On the other hand, you can safely emit signals from your QThread::run() implementation, because signal emission is thread-safe.

So my question is, is the design described above thread-safe? Can I safely call myQObject->EmitMySignal() , which in turns will call emit signalMySignal() , all this from inside the pthread object?

I will demonstrate how to achieve what you want with events instead of signals and slots that you cannot use (because one side is not QObject derived)

class MyObjectClass : public QObject
{
    Q_OBJECT
public:
    virtual bool event(QEvent *event) override
    {
        bool result = true;

        if(event->type() == QEvent::User+1)
            emit signalStatusChange(_status);
        else
            result = QObject::event(event); //call direct parent's event here!

        return result;
    }
};

And in your other thread you will do this:

MyObjectClass *p; //holds pointer to the instance in main thread
qApp->postEvent(p, new QEvent(QEvent::User+1));

This will retrieve pointer to the app that lives in the main thread and post event to its event loop. The event will be processed asynchronously from the call however so the behaviour will be different than what you are doing now. But it will be safer and imho more elegant. You can add as many types as you need. Do not forget to propagate the event to the parent if you have not handled it though!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM