multithreading - 为什么没有 Qt 连接模式在 Qt::DirectConnection 和 Qt::BlockingQueuedConnection 之间自动选择?

标签 multithreading qt signals-slots

以下是 Qt 信号/插槽连接的工作原理:

  • Direct Connection当发出信号时,立即调用该插槽。该槽在发射器的线程中执行,它不一定是接收器的线程。
  • Queued Connection当控制返回到接收者线程的事件循环时调用该槽。该槽在接收者的线程中执行。
  • Blocking Queued Connection槽的调用与排队连接一样,除了当前线程阻塞,直到槽返回。
    注意:使用该类型连接同一个线程中的对象会导致死锁。

  • 还有一个实际上是默认的:Auto Connection如果信号在接收对象具有关联的线程中发出,则行为与直接连接相同。否则,行为与排队连接相同。”

    在大多数情况下,默认值按预期工作得很好:
  • 如果在工作线程中,通过排队连接排队执行
  • 如果在对象线程中,则立即执行

  • 但是,当从线程发出信号时,您有两种选择来处理它:“排队”或“阻塞排队”连接。

    为什么没有这样的模式:
  • 如果在工作线程中,阻塞 排队执行
  • 如果在对象线程中,则立即执行

  • 因为,正如文档中提到的,使用 Blocking Queued Connection在同一个线程中会导致死锁......所以处理起来真的很痛苦,我经常不得不在我的代码中创建和管理两个信号和连接来处理:
    class A
    {
        Q_OBJECT
    public:
        A()
        {
            connect( this, SIGNAL(changedFromThread()), this, SLOT(update()), Qt::BlockingQueuedConnection );
            connect( this, SIGNAL(changedNotFromThread()), this, SLOT(update()) );
        }
    
        void notifySomethingChanged()
        {
            if ( QObject().thread() != thread() )
                emit changedFromThread(); // would dead-lock if in same thread
            else
                emit changedNotFromThread();
        } 
    
    public slots:
        void update()
        {
            // Do some changes to A that cannot be done from a worker thread
        }
    
    signals:
        void changedFromThread();
        void changedNotFromThread();
    };
    

    如果这样的模式(我们称之为 Qt::AutoBlockingConnection 可用),我可以写:
    class A
    {
        Q_OBJECT
    public:
        A()
        {
            connect( this, SIGNAL(changedFromThread()), this, SLOT(update()), Qt::AutoBlockingConnection );        
        }
    
        void notifySomethingChanged()
        {
            emit changedFromThread(); // would dead-lock if in same thread
        } 
    
    public slots:
        void update()
        {
            // Do some changes to A that cannot be done from a worker thread
        }
    
    signals:
        void changedFromThread();
    };
    

    为什么只提供线程友好的连接以在 Qt::DirectConnection 之间进行交换有什么好的理由吗?和 Qt::QueuedConnection但没有在 Qt::DirectConnection 之间交换和 Qt::BlockingQueuedConnection ?

    最佳答案

    我猜 Qt 开发团队根本不希望您指定连接类型。
    我可以理解这种设计,从某种意义上说,故意阻塞几乎总是应该避免的,如果你阻塞 UI 线程,更是如此。

    如果您想同步 2 QObject生活在不同的线程中,在它们中使用信号和槽,并相应地连接它们。

    但是,如果您处于主从方案(通常 QMainWindow 拥有 QObjectQObject::moveToThread(new QThread) ),您可以:

  • 收听来自 QObject 的信号进入您的 QMainWindow
  • 调用 QObject插槽使用 QMetaObject::invokeMethod进入QMainWindow ,所以方法调用被异步处理QObject线。
  • 关于multithreading - 为什么没有 Qt 连接模式在 Qt::DirectConnection 和 Qt::BlockingQueuedConnection 之间自动选择?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46280830/

    相关文章:

    qt - 当鼠标指针位于 QwtPlot 上时,如何更改所使用的光标?

    c++ - 在线程应用程序中从 QtScript 调用的 Qt 槽

    java - Java 中的线程作业

    multithreading - 双核超线程 : Should I use 4 threads or 3 or 2?

    c# - 无效操作异常 : The calling thread cannot access this object because a different thread owns it.

    Qt 使用 ShaderEffect 进行 QImage 渲染

    c++ - 如何在Qt中检测和替换非ascii字符?

    ios - 细胞使用随机图像

    c# - (如何)是否可以绑定(bind)/重新绑定(bind)一个方法来与不同签名的委托(delegate)一起工作?

    python - wxpython 中的事件绑定(bind)仅适用于最后一个