Timers cannot be ####### from another thread
-
I log all errors to a file during my applications life, I am seeing quite a few:
QObject::killTimer: Timers cannot be stopped from another thread QObject::startTimer: Timers cannot be started from another thread
In the output, I've tried to establish what is causing this because everywhere I use a timer I use a signal when it's done with and the slot is the place where the timer is stopped, same goes for starting so I'm scratching my head a to why this is still occurring.
Can anyone help?
-
I log all errors to a file during my applications life, I am seeing quite a few:
QObject::killTimer: Timers cannot be stopped from another thread QObject::startTimer: Timers cannot be started from another thread
In the output, I've tried to establish what is causing this because everywhere I use a timer I use a signal when it's done with and the slot is the place where the timer is stopped, same goes for starting so I'm scratching my head a to why this is still occurring.
Can anyone help?
-
@SPlatten This warning indicates that you are using some QObject in a thread it does not belong to, and it indicates it because the QObjects are not thread-safe
@eyllanesc , thank you, I thought specifically it was telling me that the timers had been stopped and started in a thread, but I cannot see this?
-
@eyllanesc , thank you, I thought specifically it was telling me that the timers had been stopped and started in a thread, but I cannot see this?
-
@SPlatten Internals of QObjects(and eventloop) use timers, and that is what is happening. That is why QObjects cannot be thread-safe: they handle many, many elements internally
@eyllanesc Sounds like a mine field...how can I trace where the issue is or what the cause is?
-
Hi,
Where do you have that timer ?
What object owns it ?
When do you create that timer ?
Are you using moveToThread with the object where you have that timer ? -
Hi,
Where do you have that timer ?
What object owns it ?
When do you create that timer ?
Are you using moveToThread with the object where you have that timer ?@SGaist , In the application that is reporting the problems:
There is only one instance of QTimer defined in the class clsMsgTrkr, this is created and started in the constructor:
mptmrMonitor = new QTimer(this); QObject::connect(mptmrMonitor, &QTimer::timeout, this, &clsMsgTrkr::onTimeout); mptmrMonitor->start(clsMsgTrkr::mscuint16AckTimeout);
The only other reference to this timer is in the slot onCleanup:
void clsMsgTrkr::onCleanup() { if ( mptmrMonitor != nullptr ) { if ( mptmrMonitor->isActive() == true ) { mptmrMonitor->stop(); } delete mptmrMonitor; mptmrMonitor = nullptr; }
This slot is connected to a signal cleanup:
//Connect cleanup signal QObject::connect(this, &clsMsgTrkr::cleanup, this, &clsMsgTrkr::onCleanup);
This is also in the class constructor. I think I may have realised where the issue is, an instance of this class is created when a message is sent, I will look into how this is done now, I think modifying the constructor to emit a signal to create and start the timer would fix the issue.
-
Is that class used in a threading context ?
-
@SGaist , yes, messages are sent by a thread, but the actual way messages are sent is:
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 ) { //Create entry to monitor status of this message // new clsMsgTrkr(this, objJSON); } } //Writes message to socket emit write(objJSON);
However as you can see above the call the new clsMsgTrkr is commented out so I'm wasn't actually using it anyway, so that's not the problem, I'm back to the original question, that's the only class that is using QTimer and it isn't used, so why am I getting those messages?
-
Possibly related to sockets.
-
@SGaist , I've tried to make my threads as simply as possible and use signals, here is the body of a thread that handles the message sending:
void clsMsgSender::run() { //Default last state to connected as it won't be! QTcpSocket::SocketState sckCurState; while( mblnRun == true ) { //Sleep to allow a small cap between transmission QThread::usleep(100); quint16 uint16Port; if ( mpModule == nullptr || (uint16Port = mpModule->uint16Port()) == 0 ) { //No module, do nothing! continue; } sckCurState = mpsckClient->state(); if ( meSckState != sckCurState ) { meSckState = sckCurState; if ( !(meSckState == QAbstractSocket::ConnectedState || meSckState == QAbstractSocket::ConnectingState) ) { emit tryToConnect(clsMsgSender::strGetLocalIP(), uint16Port); } } if ( meSckState != QAbstractSocket::ConnectedState ) { continue; } QJsonObject objJSON = objAnythingToDo(); if ( objJSON.isEmpty() == true ) { //Nothing to do...yet! continue; } // //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 ) { // //Create entry to monitor status of this message //// new clsMsgTrkr(this, objJSON); // } // } //Writes message to socket emit write(objJSON); } mblnStopped = true; }
I use mutex's in the class methods:
QJsonObject clsMsgSender::objAnythingToDo() { QMutexLocker lock(&mMutex); QTcpSocket::SocketState sckState = mpsckClient->state(); QJsonObject objJSON; if ( sckState == QAbstractSocket::ConnectedState ) { //Check if there is anything waiting in the send later objJSON = clsModule::objSendLater(); //Anything waiting to send as soon as connection is established? if ( objJSON.isEmpty() == true && mqueMsgsOut.isEmpty() != true ) { objJSON = mqueMsgsOut.dequeue(); } } return objJSON; }
-
@SGaist , I've tried to make my threads as simply as possible and use signals, here is the body of a thread that handles the message sending:
void clsMsgSender::run() { //Default last state to connected as it won't be! QTcpSocket::SocketState sckCurState; while( mblnRun == true ) { //Sleep to allow a small cap between transmission QThread::usleep(100); quint16 uint16Port; if ( mpModule == nullptr || (uint16Port = mpModule->uint16Port()) == 0 ) { //No module, do nothing! continue; } sckCurState = mpsckClient->state(); if ( meSckState != sckCurState ) { meSckState = sckCurState; if ( !(meSckState == QAbstractSocket::ConnectedState || meSckState == QAbstractSocket::ConnectingState) ) { emit tryToConnect(clsMsgSender::strGetLocalIP(), uint16Port); } } if ( meSckState != QAbstractSocket::ConnectedState ) { continue; } QJsonObject objJSON = objAnythingToDo(); if ( objJSON.isEmpty() == true ) { //Nothing to do...yet! continue; } // //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 ) { // //Create entry to monitor status of this message //// new clsMsgTrkr(this, objJSON); // } // } //Writes message to socket emit write(objJSON); } mblnStopped = true; }
I use mutex's in the class methods:
QJsonObject clsMsgSender::objAnythingToDo() { QMutexLocker lock(&mMutex); QTcpSocket::SocketState sckState = mpsckClient->state(); QJsonObject objJSON; if ( sckState == QAbstractSocket::ConnectedState ) { //Check if there is anything waiting in the send later objJSON = clsModule::objSendLater(); //Anything waiting to send as soon as connection is established? if ( objJSON.isEmpty() == true && mqueMsgsOut.isEmpty() != true ) { objJSON = mqueMsgsOut.dequeue(); } } return objJSON; }
@SPlatten said in Timers cannot be ####### from another thread:
clsMsgSender
Is that a QThread subclass ?
Where do you create the socket ? -
@SPlatten said in Timers cannot be ####### from another thread:
clsMsgSender
Is that a QThread subclass ?
Where do you create the socket ?@SGaist, here is part of the prototype:
class clsMsgSender : public QObject { Q_OBJECT ... }
And the constructor:
clsMsgSender::clsMsgSender(clsModule* pModule) : mblnRun(true), mblnStopped(false) , meSckState(QAbstractSocket::ConnectedState) , mpModule(nullptr) , mpsckClient(nullptr) , mpThread(nullptr) { setModule(pModule); clsMsgSender::mspService = this; QObject::connect(this, &clsMsgSender::tryToConnect ,this, &clsMsgSender::onTryToConnect, Qt::DirectConnection); QObject::connect(this, &clsMsgSender::removeTrkrs ,this, &clsMsgSender::onRemoveTrkrs, Qt::DirectConnection); QObject::connect(this, &clsMsgSender::sendJSON ,this, &clsMsgSender::onSendJSON, Qt::DirectConnection); QObject::connect(this, &clsMsgSender::startService ,this, &clsMsgSender::onCreateMsgSndrThrd, Qt::DirectConnection); QObject::connect(this, &clsMsgSender::write ,this, &clsMsgSender::onWrite, Qt::DirectConnection); mpsckClient = new QTcpSocket(this); QObject::connect(mpsckClient, &QTcpSocket::connected ,this, &clsMsgSender::onConnected); QObject::connect(mpsckClient, &QAbstractSocket::errorOccurred ,this, &clsMsgSender::onErrorOccurred); QObject::connect(mpsckClient, &QTcpSocket::disconnected ,this, &clsMsgSender::onDisconnected); emit startService(); }
And the slot onCreateMsgSndrThrd:
void clsMsgSender::onCreateMsgSndrThrd() { if ( mpThread == nullptr ) { mpThread = new QThread; moveToThread(mpThread); QObject::connect(mpThread, &QThread::started, this, &clsMsgSender::run); mpThread->start(); } }
-
@SPlatten said in Timers cannot be ####### from another thread:
clsMsgSender
Is that a QThread subclass ?
Where do you create the socket ? -
@SGaist I think that "mpsckClient" was created in the same where the QThread lives (probably in the constructor) but it is using it in the thread that manages the QThread (the run method)
@eyllanesc , mpsckClient is created in the clsMsgSender constructor which is not in a thread.
-
@SGaist, here is part of the prototype:
class clsMsgSender : public QObject { Q_OBJECT ... }
And the constructor:
clsMsgSender::clsMsgSender(clsModule* pModule) : mblnRun(true), mblnStopped(false) , meSckState(QAbstractSocket::ConnectedState) , mpModule(nullptr) , mpsckClient(nullptr) , mpThread(nullptr) { setModule(pModule); clsMsgSender::mspService = this; QObject::connect(this, &clsMsgSender::tryToConnect ,this, &clsMsgSender::onTryToConnect, Qt::DirectConnection); QObject::connect(this, &clsMsgSender::removeTrkrs ,this, &clsMsgSender::onRemoveTrkrs, Qt::DirectConnection); QObject::connect(this, &clsMsgSender::sendJSON ,this, &clsMsgSender::onSendJSON, Qt::DirectConnection); QObject::connect(this, &clsMsgSender::startService ,this, &clsMsgSender::onCreateMsgSndrThrd, Qt::DirectConnection); QObject::connect(this, &clsMsgSender::write ,this, &clsMsgSender::onWrite, Qt::DirectConnection); mpsckClient = new QTcpSocket(this); QObject::connect(mpsckClient, &QTcpSocket::connected ,this, &clsMsgSender::onConnected); QObject::connect(mpsckClient, &QAbstractSocket::errorOccurred ,this, &clsMsgSender::onErrorOccurred); QObject::connect(mpsckClient, &QTcpSocket::disconnected ,this, &clsMsgSender::onDisconnected); emit startService(); }
And the slot onCreateMsgSndrThrd:
void clsMsgSender::onCreateMsgSndrThrd() { if ( mpThread == nullptr ) { mpThread = new QThread; moveToThread(mpThread); QObject::connect(mpThread, &QThread::started, this, &clsMsgSender::run); mpThread->start(); } }
-
@SPlatten move the socket creation in run. Sockets cannot be moved to other threads. They have to be created in the thread they will actually work in.
-
@SPlatten move the socket creation in run. Sockets cannot be moved to other threads. They have to be created in the thread they will actually work in.
@SGaist, @eyllanesc , do you mean:
void clsMsgSender::run() { mpsckClient = new QTcpSocket(this); QObject::connect(mpsckClient, &QTcpSocket::connected ,this, &clsMsgSender::onConnected); QObject::connect(mpsckClient, &QAbstractSocket::errorOccurred ,this, &clsMsgSender::onErrorOccurred); QObject::connect(mpsckClient, &QTcpSocket::disconnected ,this, &clsMsgSender::onDisconnected); //Default last state to connected as it won't be! QTcpSocket::SocketState sckCurState; while( mblnRun == true ) { ...
-
@eyllanesc , mpsckClient is created in the clsMsgSender constructor which is not in a thread.
@SPlatten said in Timers cannot be ####### from another thread:
@eyllanesc , mpsckClient is created in the clsMsgSender constructor which is not in a thread.
Wrong, the object creation happens in the main thread.
You always have at least one thread when you execute an application.
-
@SPlatten said in Timers cannot be ####### from another thread:
@eyllanesc , mpsckClient is created in the clsMsgSender constructor which is not in a thread.
Wrong, the object creation happens in the main thread.
You always have at least one thread when you execute an application.