Passing data between threads.
-
@jenya7 said in Passing data between threads.:
How it gets messages simultaneously in one thread?
Please read https://doc.qt.io/qt-5/qtnetwork-index.html and https://doc.qt.io/qt-5/signalsandslots.html
Qt is an asynchronous framework.@jsulm said in Passing data between threads.:
@jenya7 said in Passing data between threads.:
How it gets messages simultaneously in one thread?
Please read https://doc.qt.io/qt-5/qtnetwork-index.html and https://doc.qt.io/qt-5/signalsandslots.html
Qt is an asynchronous framework.I see. Looks like Qt takes care 90% of stuff I have to worry in embedded programming. :)
-
Just to clarify. If I instantiate 3 sockets.
static MyUDP udp_1; static MyUDP udp_2; static MyUDP udp_3; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); udp_1.Start("192.176.0.1", 8001); udp_2.Start("192.176.0.2", 8002); udp_3.Start("192.176.0.3", 8003); return a.exec(); }
How it gets messages simultaneously in one thread?
@jenya7 said in Passing data between threads.:
Just to clarify. If I instantiate 3 sockets.
Please, be kind and never do something like this!!!
Never create global static instances of
QObject
base classes!!!
This is not supported be Qt.
QApplication
,QCodeApplication
orQGuiApplication
must be create before any otherQObject
base class instance or your application will crash somehow!Do something like this:
int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); MyUDP udp_1; MyUDP udp_2; MyUDP udp_3; udp_1.Start("192.176.0.1", 8001); udp_2.Start("192.176.0.2", 8002); udp_3.Start("192.176.0.3", 8003); return a.exec(); }
-
@jenya7 said in Passing data between threads.:
Just to clarify. If I instantiate 3 sockets.
Please, be kind and never do something like this!!!
Never create global static instances of
QObject
base classes!!!
This is not supported be Qt.
QApplication
,QCodeApplication
orQGuiApplication
must be create before any otherQObject
base class instance or your application will crash somehow!Do something like this:
int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); MyUDP udp_1; MyUDP udp_2; MyUDP udp_3; udp_1.Start("192.176.0.1", 8001); udp_2.Start("192.176.0.2", 8002); udp_3.Start("192.176.0.3", 8003); return a.exec(); }
I added a signal
class UDP : public QObject { Q_OBJECT public: UDP(QObject *parent = nullptr); ////////////////////////////////////////////////////// signals: void ReadyForReader(const NET_PARAM& param, const QByteArray data); ////////////////////////////////////////////////////////// };
and in a reader I add a slot
class READER { public: READER(); public slots: void ReadyForReader(const NET_PARAM& param, const QByteArray data); };
Now in main
static UDP udp_1; static UDP udp_2; static READER reader; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QObject::connect(&udp_1, &UDP::ReadyForReader, &reader, &READER::ReadyForReader); QObject::connect(&udp_2, &UDP::ReadyForReader, &reader, &READER::ReadyForReader); udp_1.Start("192.176.0.1", 8001); udp_1.Start("192.176.0.2", 8002); return a.exec(); }
I get
C:\Qt\5.12.0\mingw73_64\include\QtCore\qobject.h:250: error: no matching function for call to 'QObject::connectImpl(const Object*&, void**, const Object*&, void**, QtPrivate::QSlotObject<void (READER::)(const NET_PARAM&, QByteArray), QtPrivate::List<const NET_PARAM&, QByteArray>, void>, Qt::ConnectionType&, const int*&, const QMetaObject*)'
return connectImpl(sender, reinterpret_cast<void **>(&signal),
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
receiver, reinterpret_cast<void **>(&slot),
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
new QtPrivate::QSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typename SignalType::ReturnType>(slot),
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
type, types, &SignalType::Object::staticMetaObject);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~What I did wrong?
-
@jenya7 said in Passing data between threads.:
static UDP udp_1;
static UDP udp_2;static READER reader;
Still static...
For signals/slots your class must be derived from QObject. Please read the documentation.
-
@jenya7 said in Passing data between threads.:
static UDP udp_1;
static UDP udp_2;static READER reader;
Still static...
For signals/slots your class must be derived from QObject. Please read the documentation.
@Christian-Ehrlicher
Thank you.
Without static I get warning - warning: no previous extern declaration for non-static variable 'udp_1'.
I can do like thisint main(int argc, char *argv[]) { UDP udp_1; UDP udp_2; READER reader; QCoreApplication a(argc, argv); QObject::connect(&udp_1, &UDP::ReadyForReader, &reader, &READER::ReadyForReader); QObject::connect(&udp_2, &UDP::ReadyForReader, &reader, &READER::ReadyForReader); udp_1.Start("192.176.0.1", 8001); udp_2.Start("192.176.0.2", 8002); return a.exec(); }
But this way the objects allocated on stack.
-
@Christian-Ehrlicher
Thank you.
Without static I get warning - warning: no previous extern declaration for non-static variable 'udp_1'.
I can do like thisint main(int argc, char *argv[]) { UDP udp_1; UDP udp_2; READER reader; QCoreApplication a(argc, argv); QObject::connect(&udp_1, &UDP::ReadyForReader, &reader, &READER::ReadyForReader); QObject::connect(&udp_2, &UDP::ReadyForReader, &reader, &READER::ReadyForReader); udp_1.Start("192.176.0.1", 8001); udp_2.Start("192.176.0.2", 8002); return a.exec(); }
But this way the objects allocated on stack.
@jenya7 said in Passing data between threads.:
But this way the objects allocated on stack.
And what's the problem with it? And if it's really a problem (for whatever reason) you can allocate them with new and delete them later on or use a shared_ptr or similar.
-
@Christian-Ehrlicher
Thank you.
Without static I get warning - warning: no previous extern declaration for non-static variable 'udp_1'.
I can do like thisint main(int argc, char *argv[]) { UDP udp_1; UDP udp_2; READER reader; QCoreApplication a(argc, argv); QObject::connect(&udp_1, &UDP::ReadyForReader, &reader, &READER::ReadyForReader); QObject::connect(&udp_2, &UDP::ReadyForReader, &reader, &READER::ReadyForReader); udp_1.Start("192.176.0.1", 8001); udp_2.Start("192.176.0.2", 8002); return a.exec(); }
But this way the objects allocated on stack.
@jenya7 You should more carefully read what others write!
As @KroMignon wrote: all QObject based class instances have to be created AFTER QCoreApplication a(argc, argv)!
And as also was mentioned here: your classes have to be subclassed from QObject to use signals/slots. Please read the links I gave you!"no previous extern declaration for non-static variable 'udp_1'." - did you include the header file?
-
@jenya7 You should more carefully read what others write!
As @KroMignon wrote: all QObject based class instances have to be created AFTER QCoreApplication a(argc, argv)!
And as also was mentioned here: your classes have to be subclassed from QObject to use signals/slots. Please read the links I gave you!"no previous extern declaration for non-static variable 'udp_1'." - did you include the header file?
@jsulm said in Passing data between threads.:
@jenya7 You should more carefully read what others write!
As @KroMignon wrote: all QObject based class instances have to be created AFTER QCoreApplication a(argc, argv)!
And as also was mentioned here: your classes have to be subclassed from QObject to use signals/slots. Please read the links I gave you!"no previous extern declaration for non-static variable 'udp_1'." - did you include the header file?
I see.
Fixedclass READER : public QObject { Q_OBJECT public: READER(QObject *parent = nullptr); public slots: void ReadyForReader(const NET_PARAM& param, const QByteArray data); };
And
#include "udp.h" #include "reader.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); UDP udp_1; UDP udp_2; READER reader; QObject::connect(&udp_1, &UDP::ReadyForReader, &reader, &READER::ReadyForReader); QObject::connect(&udp_2, &UDP::ReadyForReader, &reader, &READER::ReadyForReader); udp_1.Start("192.176.0.1", 8001); udp_2.Start("192.176.0.2", 8002); return a.exec(); }
I get - error: undefined reference to `vtable for READER'
-
@jsulm said in Passing data between threads.:
@jenya7 You should more carefully read what others write!
As @KroMignon wrote: all QObject based class instances have to be created AFTER QCoreApplication a(argc, argv)!
And as also was mentioned here: your classes have to be subclassed from QObject to use signals/slots. Please read the links I gave you!"no previous extern declaration for non-static variable 'udp_1'." - did you include the header file?
I see.
Fixedclass READER : public QObject { Q_OBJECT public: READER(QObject *parent = nullptr); public slots: void ReadyForReader(const NET_PARAM& param, const QByteArray data); };
And
#include "udp.h" #include "reader.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); UDP udp_1; UDP udp_2; READER reader; QObject::connect(&udp_1, &UDP::ReadyForReader, &reader, &READER::ReadyForReader); QObject::connect(&udp_2, &UDP::ReadyForReader, &reader, &READER::ReadyForReader); udp_1.Start("192.176.0.1", 8001); udp_2.Start("192.176.0.2", 8002); return a.exec(); }
I get - error: undefined reference to `vtable for READER'
@jenya7 said in Passing data between threads.:
I get - error: undefined reference to `vtable for READER'
Did you put your READER class into its own header file?
If so then please do a complete rebuild:- Delete build folder
- Run qmake
- Build
-
@Christian-Ehrlicher
Thank you.
Without static I get warning - warning: no previous extern declaration for non-static variable 'udp_1'.
I can do like thisint main(int argc, char *argv[]) { UDP udp_1; UDP udp_2; READER reader; QCoreApplication a(argc, argv); QObject::connect(&udp_1, &UDP::ReadyForReader, &reader, &READER::ReadyForReader); QObject::connect(&udp_2, &UDP::ReadyForReader, &reader, &READER::ReadyForReader); udp_1.Start("192.176.0.1", 8001); udp_2.Start("192.176.0.2", 8002); return a.exec(); }
But this way the objects allocated on stack.
-
@jenya7 said in Passing data between threads.:
I get - error: undefined reference to `vtable for READER'
Did you put your READER class into its own header file?
If so then please do a complete rebuild:- Delete build folder
- Run qmake
- Build
@jsulm said in Passing data between threads.:
@jenya7 said in Passing data between threads.:
I get - error: undefined reference to `vtable for READER'
Did you put your READER class into its own header file?
If so then please do a complete rebuild:- Delete build folder
- Run qmake
- Build
Yes. I do - Add->Class and it generates reader.cpp and reader.h.
Thank you. Now it's OK. -
@jenya7 said in Passing data between threads.:
But this way the objects allocated on stack.
And what's the problem with it? And if it's really a problem (for whatever reason) you can allocate them with new and delete them later on or use a shared_ptr or similar.
@Christian-Ehrlicher said in Passing data between threads.:
@jenya7 said in Passing data between threads.:
But this way the objects allocated on stack.
And what's the problem with it?
I don't know how the stack is configured and managed in a regular PC but in embedded systems it's a precious resource and there are many chances to run into a stack overflow.
-
@Christian-Ehrlicher said in Passing data between threads.:
@jenya7 said in Passing data between threads.:
But this way the objects allocated on stack.
And what's the problem with it?
I don't know how the stack is configured and managed in a regular PC but in embedded systems it's a precious resource and there are many chances to run into a stack overflow.
@jenya7 said in Passing data between threads.:
I don't know how the stack configured and managed in a regular PC but in embedded systems it's a precious resource and there are many chances to run into a stack overflow.
You should really get away from micro controller programming here. You've enough stack space, esp. on the outer most frame. Also print out the size of your UDP object - I would guess it's 8 bytes (mybe some more due to the vtable, but not that much)
-
@jenya7 said in Passing data between threads.:
I don't know how the stack configured and managed in a regular PC but in embedded systems it's a precious resource and there are many chances to run into a stack overflow.
You should really get away from micro controller programming here. You've enough stack space, esp. on the outer most frame. Also print out the size of your UDP object - I would guess it's 8 bytes (mybe some more due to the vtable, but not that much)
Well... I added a signal in UDP class
//in udp.h signals: void ReadyForReader(const NET_PARAM& param, const QByteArray data); //in udp.cpp void UDP::ReadyRead() { int size = static_cast<int>(socket->pendingDatagramSize()); udp_buffer.resize(size); QHostAddress sender; quint16 senderPort; socket->readDatagram(udp_buffer.data(), udp_buffer.size(), &sender, &senderPort); net_param.ip_str = sender.toString(); net_param.port = senderPort; emit ReadyForReader(net_param, udp_buffer); }
And a slot in READER class
class READER : public QObject { Q_OBJECT public: READER(QObject *parent = nullptr); public slots: void ReadyForReader(const NET_PARAM& param, const QByteArray data); }; //in reader.cpp void READER::ReadyForReader(const NET_PARAM& param, const QByteArray data) { qDebug() << "Message from IP: " << param.ip_str; qDebug() << "PORT: " << param.port; qDebug() << "Message number: " << counter; counter++; }
I test it - send 8Kb datagram every 1 ms (total 6425 packets) - and I get it all. If I speed up - say every 500 us - a lot of datagrams are missed.
Actually I'm happy with the result. -
Well... I added a signal in UDP class
//in udp.h signals: void ReadyForReader(const NET_PARAM& param, const QByteArray data); //in udp.cpp void UDP::ReadyRead() { int size = static_cast<int>(socket->pendingDatagramSize()); udp_buffer.resize(size); QHostAddress sender; quint16 senderPort; socket->readDatagram(udp_buffer.data(), udp_buffer.size(), &sender, &senderPort); net_param.ip_str = sender.toString(); net_param.port = senderPort; emit ReadyForReader(net_param, udp_buffer); }
And a slot in READER class
class READER : public QObject { Q_OBJECT public: READER(QObject *parent = nullptr); public slots: void ReadyForReader(const NET_PARAM& param, const QByteArray data); }; //in reader.cpp void READER::ReadyForReader(const NET_PARAM& param, const QByteArray data) { qDebug() << "Message from IP: " << param.ip_str; qDebug() << "PORT: " << param.port; qDebug() << "Message number: " << counter; counter++; }
I test it - send 8Kb datagram every 1 ms (total 6425 packets) - and I get it all. If I speed up - say every 500 us - a lot of datagrams are missed.
Actually I'm happy with the result. -
@JonB said in Passing data between threads.:
@jenya7
And you expect that at a certain rate some UDP datagrams will be dropped, right?I would be happy to get all datagrams, no dropped at all.
@jenya7
Well, yes, but that wasn't what I was checking with you :) Of course we would all be happy to receive every datagram if we could! The point being is that UDP does not guarantee delivery/receipt, so I meant you are not surprised and are happy to live/understand this is the deal with drop-outs at faster speeds? One has no idea in questions here what users do/do not know/expect. We have had punters here who implement file transfer using UDP because it's "faster", and then they're not happy when they don't get all the file contents..... -
@jenya7
Well, yes, but that wasn't what I was checking with you :) Of course we would all be happy to receive every datagram if we could! The point being is that UDP does not guarantee delivery/receipt, so I meant you are not surprised and are happy to live/understand this is the deal with drop-outs at faster speeds? One has no idea in questions here what users do/do not know/expect. We have had punters here who implement file transfer using UDP because it's "faster", and then they're not happy when they don't get all the file contents..... -
If you remove the qDebug() output I would guess a lot fewer packets are being dropped. Add one (and not three) qDebug() every 1000 packets or so to get some numbers.
-
If you remove the qDebug() output I would guess a lot fewer packets are being dropped. Add one (and not three) qDebug() every 1000 packets or so to get some numbers.
@Christian-Ehrlicher said in Passing data between threads.:
If you remove the qDebug() output I would guess a lot fewer packets are being dropped. Add one (and not three) qDebug() every 1000 packets or so to get some numbers.
Packets should be stored in a file so qDebug() is some substitution for real actions.