Unsolved QTimers and QTcpSocket cannot be started/enabled from another thread error.
-
I have 2 threads - 1. Main Thread and 2.Worker Thread.
The worker thread is used for establishing a TCP connection with the server and reading and writing of data to/from the server. The run() for the worker thread is in its constructor. The obj for the worker thread is created in the main.cpp i.e. the main thread.
I have declared QTcpSocket* socket and QTimer* timer in worker thread. And socket works perfectly fine but gives out the following tracing everytime I try to write:
"QSocketNotifier: socket notifiers cannot be enabled from another thread"
The timer starts properly, stops properly but doesn't start again when the worker thread goes back from the DISCONNECTED state to CONNECTED state via SET_CONNECTION state. It gives following error:
QObject::killTimer: timers cannot be stopped from another thread
QObject::startTimer: timers cannot be started from another threadalong with:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpSocket(0x159ea0), parent's thread is Thread(0x14f5b4), current thread is QThread(0x1541c0)I dont understand what is causing these errors since both the QTimer and QTcpSocket are declared and initiated in the worker thread.
-
"The run() for the worker thread is in its constructor" - that sounds strange!
Usually you start the thread by calling start() method.
Do you call run() before or after you create QTcpSocket and QTimer instances?Actually you do not need to use threads for networking in Qt because it is asynchronous (non blocking).
-
@jsulm
I'm sorry about not being clear in my last description of the problem.The start() call for my worker thread is in its constructor.
I do:
//in the worker.h
QTcpSocket socket;
QTimer timer;
//in the run() of worker.cpp
socket = new QTcpSocket();
timer = new QTimer();I have a doWork function which has a switch case statement with various states where:
..........
CONNECTED_STATE:
timer->start();
DISCONNECTED_STATE:
timer->stop();
socket->disconnectFromHost();I needed 2 threads so that I do not need to block the GUI which will be coded in the main thread when my worker thread loops in the SET_CONNECTION state where it tries to establish connection in a blocking way etc.
-
Can you post your code?
"QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpSocket(0x159ea0), parent's thread is Thread(0x14f5b4), current thread is QThread(0x1541c0)"
Something is definitely wrong. -
//worker thread ie named as Thread.cpp
Thread::Thread()
{
qDebug()<<"YOU ARE IN THE THREAD CONSTRUCTOR\n";
start();
}
void Thread::run()
{qDebug() << "hello from worker thread " << thread()->currentThreadId();
timer = new QTimer();
timer->setInterval(5000);
socket = new QTcpSocket();
buffer = new QBuffer();//Creation of Buffer
buffer->open(QIODevice::ReadWrite);connect(timer, SIGNAL(timeout()), this, SLOT(update()));
connect(socket, SIGNAL(disconnected()), SLOT(TCPStatus()));s = INIT_STATE;
doWork();
exec();
}void Thread::doWork() {
qDebug() << "hello from doWork() " << thread()->currentThreadId();
State k;
switch(s)
{
case INIT_STATE:
qDebug() << "INIT_STATE\n";
//This state is intentionally coded with no break statement
//so that the state machiene falls throught o the nex state
//without any trigger.
case SET_CONNECTION_STATE:
label: while(true)
{
s = SET_CONNECTION_STATE;
qDebug() << "SET_CONNECTION_STATE\n";
socket->connectToHost("192.168.1.74",502);
if(!socket->waitForConnected(5000)){
qDebug()<<"Error creating socket: "<<socket->errorString();
sleep(5);
continue;
}//end if
else{
break;
}
}//end while
case CONNECTED_STATE:
s = CONNECTED_STATE;
qDebug()<<"CONNECTED_STATE";
//start the timer
timer->start();
qDebug()<<"timer started :"<<thread()->currentThreadId();break; case DISCONNECTED_STATE: s = DISCONNECTED_STATE; qDebug() << "DISCONNECTED_STATE\n"; //release the resources. socket->disconnectFromHost(); timer->stop(); s = SET_CONNECTION_STATE; goto label; break;
}//end switch case
stateChange(k);
}void Thread::TCPStatus()
{
qDebug() << "Thread::TCPStatus\n";if (socket->state() == QTcpSocket::ConnectedState) { qDebug() << "TCPStatus::state=CONNECTED\n"; } else { qDebug() << "TCPStatus::state=DISCONNECTED\n"; s = DISCONNECTED_STATE; doWork(); }
}
void Thread::stateChange(enum State k)
{
if(k>s){
qDebug() << "Thread::setState\n";
s=k;
doWork();
}
}void Thread::update(){
qDebug() << "Thread::update()";
} -
Cat you try to call start() outside of the constructor?
I'm not sure whether calling start() inside the constructor of a thread class is supposed to work. -
Yes I tried thread.start(); in the main.cpp but the behavour is same as before.
-
I have found the following in the tracing:
//initially I have different thread ids:
hello from GUI thread 0x4c70056
hello from worker thread 0x535004a
//I trace out the thread id from doWork() and I get the worker thread id correctly
hello from doWork() 0x535004a
//I disconnect and reconnect. I get all the errors and the doWork() gives me the main thread id as the current thread id.
hello from doWork() 0x4c70056 -
I have found out what was wrong with my code:
It was a thread affinity issue.
I wasn't using QT:DirectConnection in my connect() and so the QTimer and QTcpsocket instance though declared in the worker thread have affinity to the main thread since the worker thread was instantiated and started in the main.cppAnyway, @jslum I really appreciate your help.