问题:
跨线程使用信号与槽连接,信号的发送时间间隔小于槽函数处理的时间间隔,造成的问题。
子线程下的槽函数,用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);
}
这样的话就可以直接在槽函数里,实现将发送信号的对象屏蔽和恢复。
先记录一下,后面有更好的方法再补充。。。