PDA

View Full Version : QTcpSocket as class member of QThread Issue



zyangxue
10th December 2009, 07:49
All,

In below codes, I get a QObject warning message during running:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x9cb3f98), parent's thread is BackServer(0x9ca2640), current thread is QThread(0x9c46378)


class BackServer : QThread{
public:
BackServer(QHostAddress ip, quint16 port, QObject * parent=0);
......
public slots:
void sendMsg(QString);
protected:
void run();
private slots:
void slot_newConn();
......
private:
QTcpServer * m_ser;
QTcpSocket * m_conn;
QHostAddress m_ip;
quint16 m_port;
};

void BackServer::run(){
m_ser=new QTcpServer;
connect(m_ser, SIGNAL(newConnection()), SLOT(slot_newConn()), Qt::DirectionConnect);
m_ser->listen(m_ip, m_port);
exec();
}

void BackServer::slot_conn(){
m_conn=m_ser->nextPendingConnection();
}

void BackServer::sendMsg(QString msg){
if (m_conn){
m_conn->write(msg.toUtf8()); // < -- issue occured point
m_conn->waitForBytesWritten();
}
}

I use BackServer as a member of subclass of QMainWindow:


class MainWindow{
...
private slots:
void slot_sendMsg();
void slot_startServer();


signal:
void sendMsg(QString);

private:
BackServer * m_backServer;
};

class MainWindow::MainWindow(...){
...
connect(ui->sendButton, SIGNAL(clicked()), SLOT(slot_sendMsg()));
...
}

class MainWindow::slot_startServer(){
...
m_backServer=new BackServer(ip, port);
connect(this, SIGNAL(sendMsg(QString), m_backServer, SLOT(sendMsg(QString);
m_backServer->start();
...
}

//
// whichever, the QObject create child thread occured!
//
class MainWindow::slot_sendMsg(){
#if 0
if (m_backServer && m_backServer->isRunning()){
m_backServer->sendMsg(ui->lineEdit->text());
}
#else
emit sendMsg(ui->lineEdit->text());
#endif
}


any suggestion?

attach is my Qtcode.

wysota
10th December 2009, 10:04
The QThread object lives in the main thread and not the thread it controls. Thus all its slots are executed in the context of the main thread. This causes objects created in them to live in the context of the main thread as well, including the QTcpSocket object created by nextPendingConnection(). Now the tcp server object lives in the context of the worker thread as it was created in the run() method of your thread class. So the two objects (server and socket) live in different threads yet the socket is a child of the server. That causes the warning. You need to make sure the socket is created in the context of the same thread as the server object.

zyangxue
11th December 2009, 04:07
Thank you, wysota.

According your remind, I had fixed the issue via QObject.moveToThread()! please see attachment!


void BackServer::newConn(){
m_conn=m_ser->nextPendingConnection();
...
m_conn->setParent(NULL);
m_conn->moveToThread(QApplication::instance()->thread());
}

tanderson
11th December 2009, 17:11
did that fix it? I might be missing something but isn't m_conn already in QApplication::instance()->thread()?

I thought this article was great. It's deal with database, but it is really about threads.
http://www.linuxjournal.com/article/9602

zyangxue
12th December 2009, 06:42
To tanderson:

Yes, I have fixed it!

The QApplication:instance()->thread() get the main thread of application, so we can move m_conn into main thread via QObject->moveToThread(). Actually m_conn will been moved into main thread after call that.
If you want move a object into other thread except main thread, must pass the pointer of destination thread into moveToThread().

A object is live in background thread, if it created in that thread.