Timer with Lambda function
-
I am sending JSON messages between processes and I want start a timer when the message is sent, if no acknowledge is received then the timer will timeout and the same message will be written again, at least that's the intention.
I have a structure:
typedef struct { QJsonObject objMsg; QTimer* pTimer; } tAckMsgTracking; typedef std::map<qulonglong, tAckMsgTracking*> mmpAck;
The map is keyed by a message transaction ID which is uniquely generated when the message is sent. The problem I'm having is that the lambda slot does not get called:
tAckMsgTracking* pAckMsgTrkr = new tAckMsgTracking; pAckMsgTrkr->objMsg = objJSON; pAckMsgTrkr->pTimer = new QTimer(this); QObject::connect(pAckMsgTrkr->pTimer, &QTimer::timeout, [this, pAckMsgTrkr]() { //Re-send message emit write(pAckMsgTrkr->objMsg); }); //Insert a unique message ID into the message objJSON.insert(clsJSON::mscszMsgID, QString::number(++clsMsgSender::msulnglngMsgID)); //Insert entry into the map clsMsgSender::msmpAcks.insert(std::make_pair(clsMsgSender::msulnglngMsgID, pAckMsgTrkr)); //Start the timer that will resend message if ack. not received pAckMsgTrkr->pTimer->start(clsMsgSender::mscuint16AckTimeout);
The value of 'mscuint16AckTimeout' is 5000 (milliseconds). I've also tried:
pAckMsgTrkr->pTimer->start(std::chrono::milliseconds(clsMsgSender::mscuint16AckTimeout));
I have a break point in the lambda slot, it doesn't get hit.
-
@SPlatten said in Timer with Lambda function:
pAckMsgTrkr->pTimer = new QTimer(this);
Not related, but: why do you allocate timer on the heap?
So, you don't get acknowledge and timeout slot is not called?
-
@SPlatten said in Timer with Lambda function:
what else would you suggest?
Make it member instead of a pointer? What's the point to have it as pointer allocate memory on the heap (which is slower) and then care to not to forget to delete it?
-
@SPlatten said in Timer with Lambda function:
I have a break point in the lambda slot, it doesn't get hit.
There are only 2 things why slot is not called:
- the thread in which the
QTimer
in living does not have a running event loop - the event loop is locked (by a
QThread::sleep()
or a forever loop)
- the thread in which the
-
I've re-written the code instead of a structure:
class clsMsgTrkr : QTimer { private: static const quint16 mscuint16AckTimeout = 5000; static mmpAck msmpAcks; QJsonObject mobjMsg; clsMsgSender* mpMsgSndr; public: clsMsgTrkr(clsMsgSender* pMsgSndr, const QJsonObject& crobjJSON) { setInterval(mscuint16AckTimeout); mobjMsg = crobjJSON; mpMsgSndr = pMsgSndr; //Add tracker to list clsMsgTrkr::msmpAcks.insert(std::make_pair(clsMsgSender::ulnglngGetMsgID(), this)); QObject::connect(this, &QTimer::timeout, [this]() { qdbg() << "TIMEOUT!"; //Re-send message emit mpMsgSndr->write(mobjMsg); }); start(); } };
I can see in the debugger the constructor is getting called and processed the timer is started but I don't get anything in the slot.
-
I added a call after call:
start(); qdbg() << this->isActive();
qdbg is just a macro I use which is:
#define qdbg() qDebug().noquote().nospace()
In the Application Output I see true so the timer is active, but doesn't timeout. Also, I just set the timer interval to 0, still no change, no timeout signal occurs.
-
@SPlatten said in Timer with Lambda function:
In the Application Output I see true so the timer is active, but doesn't timeout. Also, I just set the timer interval to 0, still no change, no timeout signal occurs.
Do you have a forever loop in your code or do you use
QThread::sleep()
?
Are you sureQEventLoop
of the used thread is working? -
@KroMignon, the message transmission is in a thread and there very short sleep in the thread loop:
void clsMsgSender::run() { QJsonObject objJSON; while( blnAnythingToDo(objJSON) == true ) { //Sleep to allow a small cap between transmission QThread::usleep(100); //Look for a module name in the message QJsonObject::iterator itrFound = objJSON.find(clsJSON::mscszMsgType); if ( itrFound != objJSON.end() ) { const QJsonValueRef crobjMsgType = itrFound.value(); QString strMsgType(crobjMsgType.toString()); if ( strMsgType.compare(clsJSON::mscszAck) != 0 ) { //Insert a unique message ID into the message objJSON.insert(clsJSON::mscszMsgID, QString::number(++clsMsgSender::msulnglngMsgID)); //Create entry to monitor status of this message new clsMsgTrkr(this, objJSON); } } //Writes message to socket emit write(objJSON); } emit queueEmpty(); }
-
@SPlatten I've told you many times to read basic Qt documentation.
this cannot work!!!
First, I suppose clsMsgSender is subclassing
QThread
. And you have create your ownrun()
implementation. So there is no running QEventLoop. This means, all QObject which are running in this thread can NOT receive/emit signals.Second, you have a forever loop, so even if there where a running
QEventLoop
, it will not be called! -
@SPlatten said in Timer with Lambda function:
I'm impatient,
Perhaps you are impatient, but in fact you are losing days doing nonsense code which not working.
If that is the best way to work, I am pretty sure NO.Reading this document would take you 1 or 2 hours, how many hours have you spend to create those non working code?
-
@SPlatten said in Timer with Lambda function:
I just don't want to stop what I'm doing to spend what would seem a long time to digest the documentation
So, instead you waste your time here?
I really don't get the logic...