PDA

View Full Version : QTcpServer::waitForNewConnection question/problem



khaake
22nd February 2007, 16:05
I have an existing, rather large, mostly non-GUI application (originally using Qt3 primarily for the limited GUI, the cross-platform socket stuff and the STL wrappers) for which I have a couple of server sockets running in separate threads. I am in the process of converting everything to Qt4 and seem to have run into a problem with QTcpServer (and QTcpSocket).

I am currently not using an event loop in my server socket threads, and instead I am using:

if (m_pListeningSocket->isListening() == true)
{
while (m_pListeningSocket->waitForNewConnection(-1) == true)
{
QTcpSocket *pTcpSocket = m_pListeningSocket->nextPendingConnection();
if (pTcpSocket != NULL)
{
// handle the new connection here
}
}
}

The problem shows up when I attempt to shutdown this thread (from another thread). I am trying to shutdown the server socket thread by having another thread call:

if (m_pListeningSocket != NULL)
{
m_pListeningSocket->close();
}

Note that the server socket thread is in the waitForNewConnection(-1) call when this happens.

The problem is that sometimes (not always) an access violation occurs in the server socket thread when close() is called. Oh, I am using microsoft Visual Studio 2005 for this development work, if that makes a difference.

What I expected to happen in this case is that waitForNewConnection() would return false once close() was called, which would eventually lead to my thread shutting itself down by exiting run(). This seems to happen sometimes, but not always.

Another interesting tidbit is that waitForNewConnection(), when it doesn't crash, actually returns 'true' the first time after close() is called (nextPendingConnection() returns NULL in this case). The second time it returns false, as expected.

I realize I could just modify my above loop condition, reduce the timeout time, and have the other thread set a variable (instead of directly calling close()) to cause the loop to exit once waitForNewConnection() times out, but I found the waitForNewConnection() behavior to be strange.

A similar 'close()' issue also seems to be present if QTcpSocket::waitForReadyRead(-1) has been called in a client socket thread and a different thread calls close() on the same QTcpSocket object. waitForReadyRead() does not return in this case unless the client application closes the socket, at which time a crash occurs.

My questions are:

1. Am I doing something incorrect or unexpected here? I'd like to stay away from directly using the signal/slot mechanism if I can. My application is structured to assume blocking socket read() operations and it would be major pain at this point to modify it to behave otherwise.

2. Is it possible for more than one thread to use a QTcpServer or QTcpSocket object if the blocking waitForX() routines are in use?

Bitto
22nd February 2007, 18:28
You can't call close() from another thread... these classes aren't thread safe. That also means you cannot call it from the QThread's destructor, if the QTcpServer or QTcpSocket was created from inside run().

Check out this doc, it's pretty good reading when you're writing theaded code with Qt.

http://doc.trolltech.com/4.2/threads.html#qobject-reentrancy

khaake
22nd February 2007, 19:34
Thanks Bitto.