PDA

View Full Version : Threaded Sever Problem



Moppel
11th November 2006, 23:20
Hi there,

I playing around with an threaded server. I had a look at the threaded fortune example which was a good start.
The different result I'm after is a worker which doesn't only returns a string but stays alive for longer.
To make life even more complicate I have a resource which can't be shared. Lets say the response a client gets is dependent on the state of this resource and this state may change from the requests it receives from the connected clients.
I have created some sort of sequence diagram of what I like to achieve.
I also attach the complete code (it's a small example) which can be build and run with `qmake && make && ./server`
The server will listen on port 6446 but this can be changed in the source code.
In case the port is not changed you may connect with `telnet localhost 6446`.


>telnet localhost 6446
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
soso
Server received: soso

salamander
Server received: salamander


Now the part I don't understand



#:~/projects/Qt4/server> ./server
new connection id: 8
Worker running
QTcpSocket::
QNativeSocketEngine::
QSocketNotifier::
received data
going to create response!
send answer
flushed socket
################## ! ! ! ! #####################
QObject: Cannot create children for a parent that is in a different thread.
QSocketNotifier: socket notifiers cannot be disabled from another thread
#^#^#^#^############## ! ! ! ! #################
new connection id: 12
Worker running
QTcpSocket::
QNativeSocketEngine::
QSocketNotifier::
received data
going to create response!
send answer
flushed socket
################## ! ! ! ! #####################
QObject: Cannot create children for a parent that is in a different thread.
QSocketNotifier: socket notifiers cannot be disabled from another thread
#^#^#^#^############## ! ! ! ! #################
received data
going to create response!
send answer
flushed socket


After quite a bit of tinkering about I found out where this QObject warning comes from.
It doesn't really help me though and about that SocketNotifier error I'm complete lost.



gdb - output
Breakpoint 2, QObject (this=0x8059260, parent=0x8056ca8) at qobject.cpp:619
619 qWarning("QObject: Cannot create children for a parent that is in a different thread.");
(gdb) backtrace
#0 QObject (this=0x8059260, parent=0x8056ca8) at qobject.cpp:619
#1 0x4022ffaa in QSocketNotifier (this=0x8059260, socket=12, type=Write, parent=0x8056ca8) at qsocketnotifier.cpp:124
#2 0x400978e3 in QNativeSocketEngine::setWriteNotificationEnabled (this=0x8056ca8, enable=true)
at qnativesocketengine.cpp:915
#3 0x400a5681 in QAbstractSocket::writeData (this=0x8058f08, data=0x805a3e0 "Server reseived: soso\r\n\n", size=24)
at qabstractsocket.cpp:1761
#4 0x401ae99b in QIODevice::write (this=0x8058f08, data=0x805a3e0 "Server reseived: soso\r\n\n", maxSize=24)
at qiodevice.cpp:1241
#5 0x40081969 in QIODevice::write (this=0x8058f08, data=@0xbfffe950) at qiodevice.h:105
#6 0x401b5438 in QTextStreamPrivate::flushWriteBuffer (this=0x8059298) at qtextstream.cpp:617
#7 0x401b66c1 in ~QTextStream (this=0xbfffe9c0) at qtextstream.cpp:1019
#8 0x0804b115 in Worker::respond (this=0x8057ce8) at worker.cpp:82
#9 0x0804ae92 in Worker::bufferData (this=0x8057ce8) at worker.cpp:59
#10 0x0804b384 in Worker::qt_metacall (this=0x8057ce8, _c=InvokeMetaMethod, _id=0, _a=0x805a430) at moc_worker.cpp:66
#11 0x40223e57 in QObject::event (this=0x8057ce8, e=0x805a1d8) at qobject.cpp:1022
#12 0x40210a72 in QCoreApplicationPrivate::notify_helper (this=0x804e130, receiver=0x8057ce8, event=0x805a1d8)
at qcoreapplication.cpp:613
#13 0x40210881 in QCoreApplication::notify (this=0xbfffef30, receiver=0x8057ce8, event=0x805a1d8)
at qcoreapplication.cpp:571
#14 0x402148cb in QCoreApplication::sendEvent (receiver=0x8057ce8, event=0x805a1d8) at qcoreapplication.h:183
#15 0x402114e6 in QCoreApplication::sendPostedEvents (receiver=0x0, event_type=0) at qcoreapplication.cpp:1022
#16 0x4023e1f5 in postEventSourceDispatch (s=0x8056968) at qeventdispatcher_glib.cpp:250
#17 0x4050ffc7 in g_main_context_dispatch () from /opt/gnome/lib/libglib-2.0.so.0
#18 0x40512392 in g_main_context_acquire () from /opt/gnome/lib/libglib-2.0.so.0
#19 0x405124a3 in g_main_context_iteration () from /opt/gnome/lib/libglib-2.0.so.0
#20 0x4023f183 in QEventDispatcherGlib::processEvents (this=0x8055800, flags={i = 20}) at qeventdispatcher_glib.cpp:363
---Type <return> to continue, or q <return> to quit---
#21 0x4020df81 in QEventLoop::processEvents (this=0xbfffeed0, flags={i = 20}) at qeventloop.cpp:125
#22 0x4020e06d in QEventLoop::exec (this=0xbfffeed0, flags={i = 0}) at qeventloop.cpp:171
#23 0x40210cda in QCoreApplication::exec () at qcoreapplication.cpp:720
#24 0x08049f85 in main (argc=1, argv=0xbfffefd4) at main.cpp:11


It looks like the warning is issued when a new SocketNotifier is to be created.

My wild guess is that it has something to do with the way and where I'm creating the QTcpSocket and the QTextStream using it.
But at the moment I'm complete glueless and would appreciate very much if someone could shed some light on that for me.

Thanks!

Moppel

Below the code which I believe is most relevant. But the complete code is attached.


void Server::incomingConnection(int socketId){
qDebug() << "new connection id: " << socketId;
Worker *wrk = new Worker(this, socketId);
((QThread*)wrk)->start();
}

void Worker::run(){
qDebug() << "Worker running";
_socket = new QTcpSocket();
// _socket = new QTcpSocket(currentThread()); // Fails with
// "Cannot create children for a parent that is in a different thread." --- Why??

_socket->setSocketDescriptor(_socketDescriptor);
_socket->dumpObjectTree();

connect(_socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)) , this, SLOT(socketStateChanged(QAbstractSocket::SocketSta te)));
connect(_socket, SIGNAL(readyRead()), this, SLOT(bufferData()));

forever{
QCoreApplication::processEvents(QEventLoop::WaitFo rMoreEvents);
}
}

void Worker::respond(){
qDebug() << "going to create response!";
QByteArray response = dad->getResourceInstance()->createResponse(buffer);
dad->releaseResourceInstance();

QTextStream os(_socket);
os << response << "\n";
qDebug() << "send answer";
_socket->flush();
qDebug() << "flushed socket";
}

jacek
12th November 2006, 02:52
((QThread*)wrk)->start();
Simple "wrk->start()" will do.


// _socket = new QTcpSocket(currentThread()); // Fails with
// "Cannot create children for a parent that is in a different thread." --- Why??
Because "current thread" object lives in a different thread. It cannot live in the newly created worker thread, because it was created before that new thread was started.


connect(_socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)) , this, SLOT(socketStateChanged(QAbstractSocket::SocketSta te)));
connect(_socket, SIGNAL(readyRead()), this, SLOT(bufferData()));
Add Qt::DirectConnection, otherwise those connections will be queued and all of the work will be done be the GUI thread, since "this" lives there.


forever{
QCoreApplication::processEvents(QEventLoop::WaitFo rMoreEvents);
}
This will process events of the GUI thread, change it to:
exec();

Moppel
12th November 2006, 23:03
Thanks jaceck!

It works!
I must admit I havn't fully understood it yet, so I better will read again
http://doc.trolltech.com/4.2/threads.html
and play around it a bit more.

Just for reference I'll attach the working sources.

Cheers Moppel

P.S. I would have liked to delete the old sources but somehow I can't do this. I can't even edit my previous posting.