QThread, QUdpSocket non-blocking
-
Hi guys,
first, i'll try my best in English, so sorry if there's some mistakes.Here is my code :
class threadCom : public QThread { Q_OBJECT public: explicit threadCom(QObject *parent = 0); void run(); private: QUdpSocket *m_socketRec; void bind(); QStack<QByteArray> *m_pileIP; public slots: void readPendingDatagrams(); };
void threadCom::bind(){ if(m_socketRec->bind(m_address, m_portRec)){ //m_address & m_portRec are set don't worry :p std::cerr << "Connected" << std::endl; connect(m_socketRec, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams())); } else{ std::cerr << "Fail" << std::endl; } }
And in my thread,
i would like to :- Wait for a new data in my QStack ( readPendingDatagrams add a QByteArray when there is a new frame in my socket)
- or wait for a timeout if there is no frame on my QStack
=>
run(){ forever{ QTimer *timer_nb = new QTimer(); timer_nb->start(500); // --- Wait for timeout or new frames in my QStack //then .... } }
That's the idea..
But i'm having trouble with threads (I'm new with this)
I guess I should use waitForReadyRead( myTimeout ) ?I tried 50 different way, none was the good one...
(Btw, I need to use Threads, because when I ask, a lot of people say I don't need threads to do that, but that's imposed !)
-
Hi @Punt, and welcome to the Qt Dev Net!
forever{ QTimer *timer_nb = new QTimer();
The
forever
loop will block the Qt event loop. If you want to use signals and slots, you cannot useforever
.I tried 50 different way, none was the good one...
Did you read the QThread documentation? There are some examples there: http://doc.qt.io/qt-5/qthread.html
(Btw, I need to use Threads, because when I ask, a lot of people say I don't need threads to do that, but that's imposed !)
Imposed by who? Why do you need to use threads?
-
@JKSH said:
Hi @Punt, and welcome to the Qt Dev Net!
Thanks !
The
forever
loop will block the Qt event loop. If you want to use signals and slots, you cannot useforever
.y, I don't use anymore
forever
, I have to useexec()
right ?Did you read the QThread documentation? There are some examples there: http://doc.qt.io/qt-5/qthread.html
I did ! But I guess i'm lost with everything I read this morning x)
(Btw, I need to use Threads, because when I ask, a lot of people say I don't need threads to do that, but that's imposed !)
Imposed by who? Why do you need to use threads?
Because I'll have a GUI, and I'll receive data to update my GUI, and I'll have to send data (with the state of my buttons on my GUI) => I'll have 2 threads, one for my UDP connexion, one for my GUI. these threads can be synchronized (When I received a new data, I signal my GUI's thread that he needs to do a loop)
-
Qt networking is asynchronous so there is usually no need for multi-threading.
-
run() //Of my UDP Thread { if(m_bloquant) //if blocking UDP connection //wait for a new frame else // non-blocking //wait for a new frame OR a timeout //then ... //share the new frame with GUI's thread //(if my 2 threads are synchronized) : emit to my GUI's thread to loop (GUI's thread will share data with UDP's thread) //Send data (in another socket udp) //loop }
that's what I want to do !
-
Another try :
void threadCom::run(){ bind(); // new QUdpSocket() & bind if(!m_bloquant){ //if non-blocking m_timer_b = new QTimer(); // QTimer connect(m_timer_b, SIGNAL(timeout()), this, SLOT(startCycle())); // One cycle + reset timer m_timer_b->start(m_timeout_b); } connect(m_socketRec, SIGNAL(readyRead()), SLOT(readPendingDatagrams())); exec(); }
void threadCom::startCycle(){ if(!m_pileIP->isEmpty()) // if data in QStack { m_dataShared->setData(m_pileIP->pop()); //share data m_pileIP->clear(); } if(m_sync) //if SYNC with GUI's thread emit needTraitement(); sendDatagrams(); //Just a cout but soon QUdpSocket_sender.write(something) if(!m_bloquant) // if non-blocking m_timer_b->start(m_timeout_b); //reset timeout }
and in ReadPendingDatagrams, I added a reset timeout too.
But this is looping just one time and doing nothing more ...
-
@Punt said:
y, I don't use anymore
forever
, I have to useexec()
right ?Right. If you want to use signals and slots, you must use
exec()
, notforever
.I did ! But I guess i'm lost with everything I read this morning x)
Threads can be tricky. I recommend that you don't use threads, unless you really really have to.
Because I'll have a GUI, and I'll receive data to update my GUI, and I'll have to send data (with the state of my buttons on my GUI) => I'll have 2 threads, one for my UDP connexion, one for my GUI. these threads can be synchronized (When I received a new data, I signal my GUI's thread that he needs to do a loop)
Well, like @jsulm said, Qt has the power to let you send/receive UDP data AND update the GUI using only one thread :)
See these simple examples:
- http://doc.qt.io/qt-5/qtnetwork-multicastreceiver-example.html
- http://doc.qt.io/qt-5/qtnetwork-multicastsender-example.html
(Or, in Qt Creator, search for the "Broadcast Sender" and "Broadcast Receiver" examples)
-
Ok, I'm not using anymore QThreads for my UDP connection,
but now I need a class with a QThread which works like that :run(){ if( myapp.isSync() ) //wait for a signal from my UDP class ... //treatment ... if( ! myapp.isSync() ) msleep( timeout ); }
Which mean, if my UDP class & this threads are synchronized, I wait a signal from my UDP class to start a loop (and then wait for another signal, etc..... =
exec()
?)
How do I do that ? -
@Punt said:
if my UDP class & this threads are synchronized
Can you describe how you planned to synchronize your threads?
run(){ if( myapp.isSync() ) //wait for a signal from my UDP class ... //treatment ... if( ! myapp.isSync() ) msleep( timeout ); }
You just need to use event-driven programming.
class UdpSignalHandler : public QObject { Q_OBJECT //... public slots: void doTreatment { //treatment } };
int main(int argc, char **argv) { QApplication app(argc, argv); // ... auto handler = new UdpSignalHandler; QObject::connect(udpSocket, &QUdpSocket::readyRead, handler, &UdpSignalHandler::doTreatment); /*--------------------------*/ /* This part is optional! */ auto thread = new QThread; handler->moveToThread(thread); thread->start(); /*--------------------------*/ // ... app.exec(); }
That's it. Now, every time the UDP socket emits a signal, your UdpSignalHandler will run the
doTreatment()
function in the other thread. Also, you don't need to ask your thread to sleep. It will automatically sleep when there are no signals.Finally, I still don't think you need threads. if you delete the code that I marked "optional", your program will still run -- all in the main thread.
(Note: My code doesn't include deleting the objects. You must handle this yourself)
-
@JKSH
I need a thread because this thread can work "not synchronized" with my UDP class.Here, when I receive a signal, I'll have to check if there is new datas shared by both class, if so treat them. Then my UdpSignalHandler will update my GUI, share other datas(the state of GUI's button for example) with my UDP class,
But if this is not-synchronized, my UdpSignalHandler will have to do all of that, all the time with a little sleep().²
-
@Punt said:
I need a thread because this thread can work "not synchronized" with my UDP class.
Sorry, I don't quite understand. Can you give an example of:
- When the two are "synchronized"?
- When the two are "not synchronized"?
Here, when I receive a signal, I'll have to check if there is new datas shared by both class, if so treat them.
The QUdpSocket will only emit the signal when there is new data, right?
If there is no new data, then UdpSignalHandler::doTreatment() will not run.
Then my UdpSignalHandler will update my GUI, share other datas(the state of GUI's button for example) with my UDP class
Note: If your UdpSignalHandler lives in another thread, then it is not allowed to read/write the GUI directly. For example, you must not call
QLabel::setText()
from another thread; you must only call it from the main thread.If the UdpSignalHandler wants to update the GUI, it must emit a signal. Then, let a GUI object's slot update the GUI.