Ошибка QObject: Cannot create children for a parent that is in a different thread
Делаю спамер пакетов по udp, дабы избежать заморозки интерфейса решил выделить поток, в результате получил следующее:
Object: Cannot create children for a parent that is in a different thread. (Parent is FileSender(0x556fd9079e80), parent's thread is QThread(0x7ffd425fea00), current thread is QThread(0x556fd8ddcae0)
spamerwidget.cpp
SpamerWidget::SpamerWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::SpamerWidget)
{
ui->setupUi(this);
connect(ui->pushButtonStartSpamming, &QPushButton::clicked,
this, &SpamerWidget::slotStartSpam);
fileSender = new FileSender();
fileSender->moveToThread(&thread);
connect(&thread, &QThread::started, fileSender, &FileSender::sendData);
}
SpamerWidget::~SpamerWidget()
{
delete ui;
delete fileSender;
}
void SpamerWidget::slotStartSpam()
{
if (!fileSender)
fileSender = new FileSender();
fileSender->param.port = this->ui->portLineEdit->text().toInt();
fileSender->param.repeatCount = this->ui->lineEditTimes->text().toInt();
fileSender->param.delay = this->ui->editdelay->text().toDouble();
fileSender->param.filePath = this->ui->filePathLineEdit->text();
fileSender->sendData();
}
filesender.h
class QUdpSocket;
class FileSender : public QObject
{
Q_OBJECT
public:
explicit FileSender(QObject *parent = nullptr);
struct parameters
{
int port;
int repeatCount;
double delay;
QString filePath;
}param;
void sendData();
void stopSendData();
public slots:
void readyWrite();
private:
static constexpr auto DATAGRAM_SIZE = 1464;
using datagram = std::array<char,DATAGRAM_SIZE>;
std::vector<datagram> datagrams;
QFile* file;
QEventLoop* eventLoop;
QUdpSocket* udpSocket;
};
filesender.cpp
FileSender::FileSender(QObject *parent)
: QObject{parent}{ }
void FileSender::sendData()
{
eventLoop = new QEventLoop(this);
udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::LocalHost, param.port);
file = new QFile(param.filePath);
if (file->isOpen())
return;
auto radioData = file->readAll();
for(auto i = 0; i < radioData.size()/DATAGRAM_SIZE - 1; ++i)
{
datagram temp;
std::copy(radioData.data() + i*DATAGRAM_SIZE,
radioData.data() + (i+1)*DATAGRAM_SIZE,
temp.begin());
datagrams.push_back(temp);
}
connect(udpSocket, &QUdpSocket::bytesWritten, this, &FileSender::readyWrite);
eventLoop->exec();
}
void FileSender::readyWrite()
{
for(auto i = 0; i < param.repeatCount; ++i)
{
for(auto j = 0u; j < datagrams.size(); ++j)
{
udpSocket->writeDatagram(datagrams[j].data(),DATAGRAM_SIZE,QHostAddress::LocalHost, param.port);
QThread::msleep(param.delay);
}
}
}
Я так понимаю есть всего два потока. Основной и тот что отвел я, причем же тогда родитель в другом потоке... В общем, не пойму что делаю не так.
Ответы (1 шт):
Проблему решил следующим образом:
spamerwidget.h
class FileSender;
QT_BEGIN_NAMESPACE
namespace Ui { class SpamerWidget; }
QT_END_NAMESPACE
class SpamerWidget : public QWidget
{
Q_OBJECT
public:
SpamerWidget(QWidget *parent = nullptr);
~SpamerWidget();
public slots:
void slotStartSpam();
signals:
void sendData();
private:
Ui::SpamerWidget *ui;
QThread thread;
FileSender* fileSender;
};
spamerwidget.cpp
SpamerWidget::SpamerWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::SpamerWidget)
{
ui->setupUi(this);
connect(ui->pushButtonStartSpamming, &QPushButton::clicked,
this, &SpamerWidget::slotStartSpam);
fileSender = new FileSender();
fileSender->moveToThread(&thread);
connect(&thread, &QThread::finished, fileSender, &QObject::deleteLater);
connect(this, &SpamerWidget::sendData, fileSender, &FileSender::sendData);
thread.start();
}
SpamerWidget::~SpamerWidget()
{
delete ui;
delete fileSender;
thread.quit();
thread.wait();
}
void SpamerWidget::slotStartSpam()
{
fileSender->param.port = this->ui->portLineEdit->text().toInt();
fileSender->param.repeatCount = this->ui->lineEditTimes->text().toInt();
fileSender->param.delay = this->ui->editdelay->text().toDouble();
fileSender->param.filePath = this->ui->filePathLineEdit->text();
emit sendData();
}
filesender.h
class QEventLoop;
class QUdpSocket;
class FileSender : public QObject
{
Q_OBJECT
public:
explicit FileSender(QObject *parent = nullptr);
struct parameters
{
int port;
int repeatCount;
double delay;
QString filePath;
}param;
public slots:
void sendData();
private:
static constexpr auto DATAGRAM_SIZE = 1464;
using datagram = std::array<char,DATAGRAM_SIZE>;
std::vector<datagram> datagrams;
QEventLoop* eventLoop;
QUdpSocket* udpSocket;
};
filesender.cpp
FileSender::FileSender(QObject *parent)
: QObject{parent}{ }
void FileSender::sendData()
{
eventLoop = new QEventLoop(this);
udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::LocalHost, param.port);
QFile file(param.filePath);
if (!file.open(QFile::ReadOnly))
return;
auto radioData = file.readAll();
for(auto i = 0; i < radioData.size()/DATAGRAM_SIZE - 1; ++i)
{
datagram temp;
std::copy(radioData.data() + i*DATAGRAM_SIZE,
radioData.data() + (i+1)*DATAGRAM_SIZE,
temp.begin());
datagrams.push_back(temp);
}
for(auto i = 0; i < param.repeatCount; ++i)
{
for(auto j = 0u; j < datagrams.size(); ++j)
{
udpSocket->writeDatagram(datagrams[j].data(),DATAGRAM_SIZE,QHostAddress::LocalHost, param.port);
QThread::msleep(param.delay);
}
}
eventLoop->exec();
}
Добавил обработку сигнала, а также соответственно запуск потока) Теперь интерфейс и отправка работают параллельно.