【问题标题】:Thread safety of calling QObject's method from another (non-qt) thread?从另一个(非 qt)线程调用 QObject 方法的线程安全?
【发布时间】:2016-12-01 17:10:19
【问题描述】:

我有两个对象存在于不同的线程中,我试图确定使用的模式是否是线程安全的。

第一个对象是 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(),而后者又会调用emit signalMySignal(),这一切都来自pthread 对象内部?

【问题讨论】:

  • 我认为您应该使用postEvent 处理这个问题,而不是像那样直接访问QObjectpostEvent 是线程安全的,如果您不想或不能使用正常的信号/插槽连接,则专为此目的而设计。
  • 发射信号是线程安全的,如前所述。但是,读取成员变量的值不是线程安全的。所以你需要保护对_status的访问,如果它是从多个线程访问的。从多个线程调用 QObject 方法很容易出错,所以如果你这样做,我建议以下几点: 1. 将方法分为“从其他线程调用”和“普通”方法,并有 不同的命名约定。 2. 以同样的方式划分成员变量,并确保对多线程使用的成员变量的访问进行互斥保护。 3. 查看代码!

标签: c++ multithreading qt


【解决方案1】:

我将演示如何使用事件而不是你不能使用的信号和槽来实现你想要的(因为一侧不是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));

这将检索指向位于主线程中的应用程序的指针并将事件发布到其事件循环。该事件将与调用异步处理,因此行为将与您现在所做的不同。但它会更安全,更优雅。您可以根据需要添加任意数量的类型。如果您还没有处理它,请不要忘记将事件传播给父级!

【讨论】:

    猜你喜欢
    • 2019-05-17
    • 2017-03-15
    • 1970-01-01
    • 2018-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多