【问题标题】:Why a signal is not being processed in receiving thread if the signalling thread is blocked?如果信号线程被阻塞,为什么在接收线程中没有处理信号?
【发布时间】:2017-11-08 15:49:10
【问题描述】:

这是在thread A 中调用的:

void MainApplication::notify()
{
    emit mySignal();
    QThread::currentThread()->sleep(5);
}

在此之前发生连接和接收器创建:

// thread A
void MainApplication::init()
{
    receiver->moveToThread(threadB);

    connect(this,
            &MainApplication::mySignal,
            receiver,
            &Receiver::onMySignal,
            Qt::QueuedConnection);
}

预期:插槽 Receiver::onMySignal()thread B 调用。
现实:在发出 thread A 睡眠时,插槽不会被调用。

P.S.:我 100% 确定thread B 的事件循环在信号发出时正在运行。

【问题讨论】:

  • 我猜信号只有在控制权返回到信号线程的事件循环时才会发送,而不是直接在您调用发出时发送,因为它是一个排队连接。
  • @xander 这也是我唯一的猜测,但我找不到证明和解决方法。
  • renderManager.data()的返回值和receiver一样吗?
  • 您的代码看起来很奇怪。renderManager.data() 是否返回对象 receiver
  • @thuga 是的,这是接收器。我复制粘贴并没有改变这一行。更新了示例。

标签: c++ multithreading qt


【解决方案1】:

其实应该的。以下简单示例可以正常工作。

class SenderObj : public QObject
{
    Q_OBJECT
signals:
    void happened();
public:
    void triggerSignal() {
        qDebug() << "Emitting 'happened'";
        emit happened();
        qDebug() << "Emitted 'happened'";
        QThread::currentThread()->sleep(5);
    }
};

class ReceiverObj : public QObject
{
    Q_OBJECT
public slots:
    void doSomething() {
        qDebug() << "SLOT called in " << QThread::currentThread();
    }
};

// In my MainWindow :
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    auto thread = new QThread(this);
    thread->start();

    m_senderObj = new SenderObj;
    m_receiverObj = new ReceiverObj;

    m_receiverObj->moveToThread(thread);
    connect(m_senderObj, &SenderObj::happened, m_receiverObj, &ReceiverObj::doSomething);
}

void MainWindow::on_pushButton_clicked()
{
    m_senderObj->triggerSignal();
}

当我点击按钮时,信号立即发出,第二个线程立即执行槽,我的主线程(MainWindow)被冻结 5 秒。

【讨论】:

  • 谢谢你,你是对的 - 我也无法在简约示例中重现该问题。经过仔细的代码库调查,我发现了这个问题,它与信号和线程无关。
【解决方案2】:

要处理此问题,您需要通过调用运行事件队列一次

QCoreApplication::processEvents();

这将触发处理来自您的线程的所有排队事件。

【讨论】:

  • 谢谢。这样就完成了。
  • 抱歉,我必须将问题标记为未回答。事实证明,对processEvents() 的一次调用并不能解决问题(请参阅follow-up question
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-29
  • 2013-11-29
  • 2020-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多