Timers cannot be ####### from another thread
-
@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.
-
And that is the issue. You are thus creating your socket in the main thread as well.
-
@SGaist , sorry, I'm not sure why you say that, the class clsMsgSender is not a socket. If you mean that:
mpsckClient = new QTcpSocket(this);
Is that the problem? because this is in the clsMsgSender constructor, then please explain what I should do because I suggested moving it into the thread and the response was no.
Can you please clarify what I'm doing wrong and how to fix it?
-
@SPlatten said in Timers cannot be ####### from another thread:
new QTcpSocket(this);
This creates an object with the parent in the main thread. And since a child must be in the same thread as the parent...
Don't pass this as parent and delete it by your own. -
@Christian-Ehrlicher for sockets you have to go one step further and ensure it's created in the thread that will actually use it.
-
@Christian-Ehrlicher for sockets you have to go one step further and ensure it's created in the thread that will actually use it.
-
Start with the QThread. There are several other chapters linked from the details of the class.
@SGaist , I've just read the details on QThread and I didn't see anything specifically regarding the use of Sockets. I then found this when searching online:
https://forum.qt.io/topic/57753/qtcpsocket-and-qthread
Obviously you are familiar with this one.https://stackoverflow.com/questions/34641732/qtcpsocket-handling-in-another-qthread
Not sure what the conclusion of the above was...https://www.bogotobogo.com/Qt/Qt5_QTcpServer_Multithreaded_Client_Server.php
Working through this....I must say the approach the last link takes is exactly the way I started, with sub-classing my listening class from QTcpServer, however after several posts here advising not to do this I changed my class.