When you emit a signal, you return control to the Qt event loop. If you do not emit any signal from within checkTimeouts(), then your loops run completely to the end and checkTimeouts() exits before control returns to the event loop. When you emit the signal, then all pending events will be processed, including any new timeouts, which means you could be entering checkTimeouts() recursively. So basically, your list gets completely screwed up.
You can probably verify this by putting some qDebug() statements at the beginning and end of checkTimeouts() and see if you get an "entering checkTimeouts()" and "exiting checkTimeouts()" occurring together in pairs of enter / exit. If you get two enters in a row, you have a second timeout being processed before the first one has finished.
Time to re-think your design. Your basic problem is that it is taking longer to process all of the pending messages than the timeout period, so your timeouts are stacking up. So if your application allows you to ignore extra timeouts, then one easy way to avoid the problem is to keep a bool member variable in your PendingList class:
void PendingList::checkTimeouts()
{
qDebug() << "Entering checkTimeouts()";
if ( !inTimeout )
{
inTimeout = true; // this is a member variable of PendingList; initialize it to false in the constructor
qint64 t1
= QDateTime::currentMSecsSinceEpoch();
for (int i = 0; i < MAX_CLIENTS; i++)
{
QList<PendingMsg>::iterator it;
for (it = list[i].begin(); it != list[i].end(); )
{
quint64 t0 = it->request.getTimeStamp();
quint64 dift = t1 - t0;
if (dift >= it->timeout)
{
CMD cmd1 = it->cmd;
CMD cmd2 = it->request.getCmd();
it = list[i].erase(it);
emitTimeout((System)i, cmd1, cmd2);
}
else
it++;
}
}
stopIfEmpty();
inTimeout = false;
}
qDebug() << "Exiting checkTimeouts()";
}
void PendingList::checkTimeouts()
{
qDebug() << "Entering checkTimeouts()";
if ( !inTimeout )
{
inTimeout = true; // this is a member variable of PendingList; initialize it to false in the constructor
qint64 t1 = QDateTime::currentMSecsSinceEpoch();
for (int i = 0; i < MAX_CLIENTS; i++)
{
QList<PendingMsg>::iterator it;
for (it = list[i].begin(); it != list[i].end(); )
{
quint64 t0 = it->request.getTimeStamp();
quint64 dift = t1 - t0;
if (dift >= it->timeout)
{
CMD cmd1 = it->cmd;
CMD cmd2 = it->request.getCmd();
it = list[i].erase(it);
emitTimeout((System)i, cmd1, cmd2);
}
else
it++;
}
}
stopIfEmpty();
inTimeout = false;
}
qDebug() << "Exiting checkTimeouts()";
}
To copy to clipboard, switch view to plain text mode
Another way to do it would be to stop the timer when you enter checkTimeouts() and start it when you exit. Or make it a single-shot, and simply restart it when you exit. That way you can be guaranteed that no new timeouts can be generated while you are processing the first one.
Bookmarks