【问题标题】:Is there a guarantee that no signals are delivered from a different thread after QObject::disconnect()?是否保证 QObject::disconnect() 之后没有信号从不同的线程传递?
【发布时间】:2013-05-11 23:33:02
【问题描述】:

我没想到disconnect()之后还在接收线程中传递排队信号的问题,而是:

考虑Sender 对象在线程 1 中生成信号并且线程 2 中有一个Receiver 对象的情况,该对象有一个插槽,通过Qt::DirectConnection 连接到Sender 的信号。

现在,在Receiver::~Receiver() 中,我需要确保在对象已经(可能部分)被破坏时仍然没有传递任何信号。因为连接是直接的,所以可以随时在线程 1 中调用插槽,特别是可能发生在 Receiver 的特定属性的破坏和基 QObject 的破坏之间,这也会断开信号。所以,我的问题归结为:

在销毁Receiver 对象之前断开线程2 中的SenderReceiver 对象是否足够,或者我是否需要确保在disconnect() 调用期间线程1 中没有发出任何信号?

我正在考虑线程 1 正在发出信号的情况,例如就在执行接收槽的顶部,就在那一刻,在线程 2 中,完成了 disconnect() 调用。如果disconnect() 等待(通过互斥体)线程 1 在断开连接并阻止进一步的信号传递之前完成信号传递,一切都会好起来的,但我不确定情况是否如此。

【问题讨论】:

    标签: qt thread-safety signals-slots


    【解决方案1】:

    是的 disconnect()connect() 正在使用互斥锁进行保护。

    这些是disconnect() 函数的第一行:

    bool QMetaObjectPrivate::disconnect(const QObject *sender, int signal_index,
                                        const QObject *receiver, int method_index,
                                        DisconnectType disconnectType)
    {
        if (!sender)
            return false;
    
        QObject *s = const_cast<QObject *>(sender);
    
        QMutex *senderMutex = signalSlotLock(sender);
        QMutex *receiverMutex = receiver ? signalSlotLock(receiver) : 0;
        QOrderedMutexLocker locker(senderMutex, receiverMutex);
    

    下面是connect() 函数的第一行:

    bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
                                     const QObject *receiver, int method_index, int type, int *types)
    {
        QObject *s = const_cast<QObject *>(sender);
        QObject *r = const_cast<QObject *>(receiver);
    
        QOrderedMutexLocker locker(signalSlotLock(sender),
                                   signalSlotLock(receiver));
    

    如果您查看QObject 文档,您会看到:

    注意:这个类中的所有函数都是可重入的,但是connect(), connect()、disconnect() 和 disconnect() 也是线程安全的。

    编辑

    当发出信号时,会调用 QMetaObject::activate 函数来锁定发送者的对象互斥锁:

    void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
                               void **argv)
    {
         ...
         QMutexLocker locker(signalSlotLock(sender));
    

    【讨论】:

    • 谢谢,是的,我看到了。我不确定的是是否使用相同的互斥锁来保护信号的传递。
    猜你喜欢
    • 1970-01-01
    • 2019-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多