2016-12-01 62 views
1

我有两个对象,它们生活在不同的线程中,我试图确定一个使用的模式是否是线程安全的。从另一个(非qt)线程调用QObject方法的线程安全性?

第一个对象是QObject派生的,并且生存在(创建于)主Qt线程中。该类包含应该从QML调用的一些Q_INVOKABLE方法,定义为signals:的一些signal*()方法和我用作包装发射信号的一些Emit*()(正常)方法。例如:

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

我通常会在QML中监听这些信号。

第二个对象是而不是 QObject派生并且存在于第二个线程中(pthread)。该线程运行自己的事件循环(libev)并分派事件。我不能在这个线程中使用任何与Qt相关的东西,因为我需要自定义的libev事件循环。在这个对象上,我定义了一些Notify*()方法,这些方法将通过libev发送异步事件以通过回调获取。

我需要能够在两个对象/线程之间进行通信,但我不确定如何安全地执行此操作。

实际的设计是让pthread线程对象直接调用不同的Emit*()方法,以便QObject可以正确地将信息传播到Qt/QML。如果我需要将信息从Qt/QML发送到pthread/libev对象,我调用(从Qt线程)Notify*()方法。

当读取Accessing QObject Subclasses from Other Threads,它说:

的QObject和所有它的子类不是线程安全的。这包括整个事件传递系统。

但再往它指出:

在另一方面,你可以安全地从你的QThread :: run()的执行情况发出信号,因为信号发射是线程安全的。

所以我的问题是,上面介绍的设计是线程安全的吗?我可以安全地拨打myQObject->EmitMySignal(),这又会来自pthread对象内的所有这些内容,这些内容又将调用emit signalMySignal()

+0

我认为你应该用'postEvent'来处理这个问题,而不是像这样直接访问'QObject'。 'postEvent'是线程安全的,如果您不想或不能使用正常的信号/插槽连接,则为此目的而设计。 – Resurrection

+0

如上所述,发射信号是线程安全的。但是,成员变量的读值不是线程安全的。因此,如果从多个线程访问它,则需要保护对“_status”的访问。从多个线程调用一个* QObject *方法是容易出错的,所以如果你这样做,我推荐几件事:1.将方法分成“从其他线程调用”和“普通”方法,并且具有*独特的命名约定*这些。 2.以相同的方式划分成员变量,并确保互斥 - 保护对多线程中要使用的成员变量的访问。 3.查看代码! – hyde

回答

0

我将演示如何实现你想要的事件,而不是说你不能使用信号和槽是什么(因为一边是不QObject派生)

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; 
    } 
}; 

而在你的其他线程,你会做到这一点:

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

这将检索指向居住在主线程中的应用程序的指针,并将事件发布到其事件循环中。该事件将与该呼叫异步处理,但行为将与您现在正在做的不同。但它会更安全,恕我直言更优雅。您可以根据需要添加尽可能多的类型。如果你还没有处理它,别忘了把事件传播给父母!

相关问题