记录一下QT movetothread多线程槽函数无法触发

刚开始接触QT,需要使用QT做一个客户端。为了不使界面卡死,选择把业务放在子线程中运行。碰到了槽函数无法触发的问题。

假如有个工作类work,如下所示。

#ifndef FFFFFFFFFFFFFFF
#define FFFFFFFFFFFFFFF

#include <QObject>
#include <QThread>
class work: public QObject
{
    Q_OBJECT
public:
    explicit work(QObject *parent = nullptr);
signals:
public slots:
    int _start()
    {
    	//耗时操作
    }
};
#endif // 

movetothread的本质并非是将work实例相关的所有的工作“移动”到了子线程,而是将所有work实例相关的事件托管到子线程执行。就是通过信号槽触发work实例中槽函数产生的事件,将会被放置到子线程中执行,从而实现了多线程工作。

问题一

解决办法:用new
一般网上的说法都是connect函数的第五个参数导致的,但是多线程的connect的第五个参数默认使用Qt::QueuedConnection,所以在我这里并不是这个问题导致的。经过分析代码,发现我这个是因为处理业务类的对象写成了局部对象,从而导致槽函数无法触发。

错误写法:

QThread *thread = new QThread(this);
**//此处是局部变量,一旦跑出这个局部函数,read将不存在,自然就不能触发槽函数**
QReadMsg read(tcpClient) ;//业务处理对象
read->moveToThread(&thread);
connect(tcpClient, &QTcpSocket::readyRead,&read,&QReadMsg::slot_ReadData);
thread->start();
emit readyRead();

正确写法:

QThread *thread = new QThread(this);
//此处使用new,放在堆中,read除非手动释放,否则一直存在,记得线程结束时候手动释放
QReadMsg *read = new QReadMsg(tcpClient);//业务处理对象
read->moveToThread(thread);
connect(tcpClient, &QTcpSocket::readyRead,read,&QReadMsg::slot_ReadData);
thread->start();
emit readyRead();

问题二

在子线程中进行业务处理,将结果放在信号中发送给父线程触发父线程的槽函数。如果信号触发过快,会导致槽函数无法触发

解决办法:在信号发送的地方延时一点时间,让槽函数能够有时间触发。或者增加一个QApplication::processEvents();

父进程

QThread *thread = new QThread(this);
//此处使用new,放在堆中,read除非手动释放,否则一直存在,记得线程结束时候手动释放
QReadMsg *read = new QReadMsg(tcpClient);
read->moveToThread(thread);//业务处理对象
connect(tcpClient, &QTcpSocket::readyRead,read,&QReadMsg::slot_ReadData);
//子线程的带参信号连接父线程的槽函数
connect(read, &QReadMsg ::displayRecvData,this,[=](QString str ){
	ui->linetest.setText(str );
});
thread->start();
emit readyRead();

子进程
方法一:

while(1){
	/读取数据
	emit displayRecvData();//触发信号
	//增加延迟函数
	QThread::sleep(2);
}

方法二:

while(1){
	/读取数据
	emit displayRecvData();//触发信号
	//
	QApplication::processEvents();
}

问题三,步骤都对,但是子线程ID和主线程ID相同

2021/4/23=======偶然发现一个问题
moveToThread以后,界面还是假死,子线程ID和主线程ID相同,没有在新线程中处理业务。
错误写法:

QThread *thread = new QThread(this);
//此处使用new,放在堆中,read除非手动释放,否则一直存在,记得线程结束时候手动释放
QReadMsg *read = new QReadMsg(this);//业务处理对象
read->moveToThread(thread);
connect(tcpClient, &QTcpSocket::readyRead,read,&QReadMsg::slot_ReadData);
thread->start();
emit readyRead();

注意QReadMsg *read = new QReadMsg(this),这个地方不能传入this。
如果传入this,业务就被托管this的线程中了,即还是在主线程。
正确写法:

QThread *thread = new QThread(this);
//此处使用new,放在堆中,read除非手动释放,否则一直存在,记得线程结束时候手动释放
QReadMsg *read = new QReadMsg;//业务处理对象
read->moveToThread(thread);
connect(tcpClient, &QTcpSocket::readyRead,read,&QReadMsg::slot_ReadData);
thread->start();
emit readyRead();

正确写法:QReadMsg *read = new QReadMsg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值