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

jpo*_*o38 5 qt multithreading signals-slots

这是Qt信号/插槽连接的工作方式:

  • 直接连接发出信号后立即调用插槽。该插槽在发射器的线程中执行,而不一定是接收器的线程。
  • 排队连接当控制返回到接收者线程的事件循环时,将调用该插槽。该插槽在接收者的线程中执行。
  • 阻塞队列连接插槽与队列连接一样被调用,但当前线程除外,直到该插槽返回为止。注意:使用此类型连接同一线程中的对象将导致死锁。

还有一个实际上是默认值的附加值:自动连接如果信号在接收对象具有亲和力的线程中发出,则其行为与直接连接相同。否则,行为与排队连接相同。”

在大多数情况下,默认设置可以正常运行:

  • 如果在工作线程中,则通过排队连接排队执行
  • 如果在对象线程中,则立即执行

但是,从线程发出信号时,您有两个选项来处理它:“已排队”或“阻止已排队”连接。

为什么没有这样的模式:

  • 如果在工作线程中,则阻止排队执行
  • 如果在对象线程中,则立即执行

因为,正如文档所提到的,在同一线程中使用阻塞队列连接会导致死锁....所以处理起来确实很痛苦,我经常不得不在我的代码中创建和管理两个信号和连接来处理:

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();
};
Run Code Online (Sandbox Code Playgroud)

如果有这种模式(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();
};
Run Code Online (Sandbox Code Playgroud)

有没有什么好的理由螺纹型连接只发给之间交换Qt::DirectConnectionQt::QueuedConnection,但没有之间的交换Qt::DirectConnectionQt::BlockingQueuedConnection

小智 0

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

如果您希望同步QObject不同线程中的两个线程,请在两个线程中使用信号和槽,并相应地连接它们。

但是,如果您处于主从场景(通常QMainWindow拥有QObjectwith QObject::moveToThread(new QThread)),您可以:

  • 聆听来自QObject您的信号QMainWindow
  • QObject使用QMetaObject::invokeMethodinto 调用槽QMainWindow,因此方法调用由QObject线程异步处理。