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

博客探讨了Qt跨线程使用信号与槽连接,当信号发送间隔小于槽函数处理间隔时产生的问题。分析发现默认采用队列传输方式,槽函数处理不及时会将信号存入队列。给出两种解决方法,一是设置为阻塞队列连接,二是用函数屏蔽信号发送,各有优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

子线程下的槽函数,用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);
}

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值