PDA

View Full Version : QThread and event loop



Crashz83
17th August 2015, 14:29
Hello,

I am a beginner in programming and i want to make an application to retieve data with UDP protocole (using QUdpSocket). I use a thread and I would like to manage event management in one.
The problem is that I have an error and I can not find any doc about this error...

Here is my server class Serveur.h:



class Serveur : public QThread
{
Q_OBJECT
public:
explicit Serveur(QThread *parent = 0);
Serveur(QString pAdr, int pPort);

void closeSocket();
void run();
private:
QUdpSocket *socket;

QHostAddress* host;
QString Address;
int Port;
public slots:
void read();
void erreurSocket(QAbstractSocket::SocketError error);

};


Serveur.cpp:



Serveur::Serveur(QString pAdr, int pPort)
{

Address = pAdr;
Port = pPort;
socket = NULL;
qRegisterMetaType<QAbstractSocket::SocketError>( "QAbstractSocket::SocketError" );
host = new QHostAddress("192.168.1.33");

}

void Serveur::closeSocket()
{
this->quit();

if( socket != NULL )
{
socket->close();
delete socket;
socket = NULL;
}
delete host;
host = NULL;
}

void Serveur::run()
{
socket = new QUdpSocket();

connect(socket, SIGNAL(readyRead()), this, SLOT(readData()));
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(erreurSocket(QAbstractSocket::SocketError)));
qDebug() << socket->thread();

socket->bind(QHostAddress(Address), Port);

exec();
}

void Serveur::erreurSocket(QAbstractSocket::SocketError error)
{
switch( error )
{
case QAbstractSocket::HostNotFoundError:
qDebug() << "Error : can't find the server. Verify ip and port.";
break;
case QAbstractSocket::ConnectionRefusedError:
qDebug() << "Error : the server refused the connection or is not connected.";
break;
case QAbstractSocket::RemoteHostClosedError:
qDebug() << "Error : the server close the connexion.";
break;
default:
qDebug() << "Error : " + socket->errorString();
}
}

void Serveur::read()
{

while(socket->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(socket->pendingDatagramSize());

quint16 senderPort = Port;
quint64 lReceive = ( socket->readDatagram(datagram.data(), datagram.size(), host, &senderPort ) );

qDebug() << "Nb bytes : " << lReceive;
}
}


When my program starts all goes well, but sometimes it crashes with the following error message:

QSocketNotifier: Invalid socket 15 and type 'Read', disabling...

However, when I create my QUdpSocket object in the class constructor, and Event management is managed in the main thread, it works.

Any ideas?

Thank you in advance, and sorry for my bad english! :)

anda_skoa
17th August 2015, 14:56
First question, as usual when threads are used: are you sure you need to use one?

Then a couple of suggestions:
- do not delete the socket in the detructor, delete it after exec() returns, i.e. within the worker thread.
- no need to make the QHostAddress a pointer
- do not make internal slots public
- be aware that your slots are currently executed in the main thread, so do not access "socket" in them

Cheers,
_

Crashz83
17th August 2015, 16:29
Thanks you for your quickly response.

Yes i need to use a thread because the frequency of data's reception is important, otherwise it would block my application.
I modified my code, but there is something I do not understand...

" - be aware that your slots are currently executed in the main thread, so do not access "socket" in them " : effectively, i added
qDebug() << this->thread(); and my slot run in the main thread. But, how I can retrieve data before the error, how can I access the socket?

In the console, i can see :



Nb byte : 936
Nb byte : 936
Nb byte : 936
Nb byte : 936
QSocketNotifier: Invalid socket 15 and type 'Read', disabling...
Nb byte : 936
Nb byte : 936
Nb byte : 936
Nb byte : 936


Sometimes this error is not blocking :confused:

anda_skoa
17th August 2015, 17:27
Yes i need to use a thread because the frequency of data's reception is important, otherwise it would block my application.

Ok, I was just checking that you had implemented it without threads first and only start using threads as a last resort.



I modified my code, but there is something I do not understand...

" - be aware that your slots are currently executed in the main thread, so do not access "socket" in them " : effectively, i added
qDebug() << this->thread(); and my slot run in the main thread. But, how I can retrieve data before the error, how can I access the socket?

Well, you should not access the socket from two threads. So it would make most sense to handle the signals of the socket in the same thread as the socket.
Either by having the receiver on the same thread or by forcing a direct call using Qt::DirectConnection as the connection type.

Currently you have the receiver on the main thread and are using the default connection type (Qt::AutoConnection) which results in the behavior of Qt::QueuedConnection (emitter thread and receiver owner thread different).

Cheers,
_

Crashz83
18th August 2015, 09:38
It's ok, I simply added a call to Qt :: DirectConnexion in the connection of slots and everything works.

Thanks you very much!! :D