刚开始接触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。