Qt信号发送过快,槽函数处理不过来解决方法

问题:
跨线程使用信号与槽连接,信号的发送时间间隔小于槽函数处理的时间间隔,造成的问题。

子线程下的槽函数,用sleep来模拟槽函数的耗时操作:

void MyThread::myTimeout()
{
    qDebug() << "test";
    QThread::sleep(2);
}

主线程下的信号发送函数,通过点击按钮来发送信号:

void Widget::on_buttonStart_clicked()
{
    emit startThread();
}

线程之间的信号连接函数:

    connect(this, &Widget::startThread, myT, &MyThread::myTimeout);

现象:在我们连续点击按钮后,能明显看到打印的信息有延时。

分析:在我们跨线程使用信号与槽时,connect函数默认是使用Qt::QueuedConnection队列的传输方式。当我们的槽函数处理不过来时,会先将传输的信号存入队列中,等槽函数处理完了再拿出来。

解决方法:
我们需要在等槽函数执行完后,才能发送新的信号。

方法一:使用connect的第五个参数,设置为Qt::BlockingQueuedConnection

槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。

    connect(this, &Widget::startThread, myT, &MyThread::myTimeout,Qt::BlockingQueuedConnection);

这个也是可以的,但是当我们子线程,处理所需时间很长时,
主线程会出现明显的卡顿,效果不太好。

方法二:
使用bool QObject::blockSignals(bool block)函数屏蔽信号发送,当槽函数处理完后,再开启。

子线程下的改动:

void MyThread::myTimeout()
{
    qDebug() << "test";
    QThread::sleep(2);
    emit recover();
}

主线程下的改动:

void Widget::on_recover()
{
    ui->buttonStart->blockSignals(false);
}

void Widget::on_buttonStart_clicked()
{
    emit startThread();
    ui->buttonStart->blockSignals(true);
}

增加信号连接函数:

    connect(this, &Widget::startThread, myT, &MyThread::myTimeout);
    connect(myT, &MyThread::recover, this, &Widget::on_recover);

通过增加对信号发送的限制,这样的话可以实现,只有在槽函数处理完成后,才会开始发送信号。

但是用这个函数有一个问题就是,这个对象的所有信号,在屏蔽的期间都不会发送了,也需要等槽函数处理完之后才能发送信号,实验代码如下。

void Widget::on_buttonStart_clicked()
{
    emit startThread();
    ui->buttonStart->blockSignals(true);
}

void Widget::on_buttonStart_pressed()
{
    qDebug() << "信号能正常触发";
}

所以如果说两个对象之间只是一对一的信号连接的话,可以使用blockSignals函数

1、屏蔽信号的方式还可以用:

void MyThread::myTimeout()
{
    QObject::sender()->blockSignals(true);
    QThread::sleep(2);
    QObject::sender()->blockSignals(false);
}

这样的话就可以直接在槽函数里,实现将发送信号的对象屏蔽和恢复。

先记录一下,后面有更好的方法再补充。。。

你可能感兴趣的:(qt,多线程,信号处理)