使用Qt的多线程时,出现 QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread 的错误。通过查询资料总结如下:
- 创建一个子线程对象是主线程的工作.也就是说在对象在哪个线程被实例化就属于哪个线程.
- 利用movetothread函数可以将对象转移至另外的线程.
- QThread的run函数属于子线程
- 信号和槽 隶属于它们所在对象的线程.
- 使用connect之后,槽函数默认执行在槽函数所在线程,若改变connect函数的第五个参数,比如设为Qt::DirectConnection,可让槽函数在信号所在线程执行.
根据以上的结论,代码报错的原因是:
- QUdpSocket对象在DataReceive的构造函数中被实例化,而DataReceive的实例化是被主线程实例化的,因此QUdpSocket也属于主线程,而QUdpSocket发出的socket通知是在主线程,对应的槽函数是在子线程.
原来的代码:
#pragma once
#ifndef DataReceive_h__
#define DataReceive_h__
#include <QObject>
#include <QByteArray>
#include "common.h"
class QUdpSocket;
class DataReceive : public QObject
{
Q_OBJECT
public:
DataReceive(QObject *parent=nullptr);
~DataReceive();
public slots:
void slotReadyRead();
void doInit();
signals:
void sigCoilData(Coils_T coils);
void sigSensorData(Sensors_T sensors);
private:
QByteArray _recv();
private:
QUdpSocket* m_pUdp = nullptr;
QByteArray _cache;
QByteArray _packet;
Coils_T _cache_coils;
Sensors_T _cache_sensors;
std::vector<int> _coils_mask{ 0,1,2,3,4,5,6,7,8,9 };
std::vector<int> _sensors_mask{ 0,1,2,3,4,5,6,7,8,9 };
};
#endif // DataReceive_h__
DataReceive::DataReceive(QObject *parent)
: QObject(parent)
{
m_pUdp = new QUdpSocket;
m_pUdp->bind(QHostAddress::LocalHost, 244);
//接收数据
bool isR = connect(m_pUdp, &QUdpSocket::readyRead, this, &DataReceive::slotReadyRead);
}
更改后:
void DataReceive::doInit() {
m_pUdp = new QUdpSocket;
m_pUdp->bind(QHostAddress::LocalHost, 244);
//接收数据
bool isR = connect(m_pUdp, &QUdpSocket::readyRead, this, &DataReceive::slotReadyRead);
}
将DataReceive构造函数中初始化upd的代码放到了doInit中,该函数被
QThread* t = new QThread;
m_dataReceive->moveToThread(t);
bool isB = connect(t, SIGNAL(started()), m_dataReceive, SLOT(doInit()));
started信号调用。