PDA

View Full Version : Multithreaded Server, Timer in QThread, Thread IDs questions



sadjoker
23rd April 2010, 12:14
Hello, in order to understand the multithreaded applications deeper i have some questions:

I have an application (server accepting clients trough SSL opening new thread for every client). Every thread makes new PSQL connection cloned from main connection with unique name.

I needed to make a QTimer to disconnect idled connections and threads so i open the new Thread with parent 0 and i call moveToThread( this ) in the thread`s constructor. The timer starts and resets in the readData() slot called from the readyRead() signal of the QSSlSocket which i open in the run() function of the inherited QThread class.

When i call currentThreadId() after moveToThread(this) the ID is the main thread`s ID... but called from run() method it shows new thread ID. When i call quit or exit the destructor of the inherited class is never called but the slot of thread`s finished signal is called and the thread id there is again main thread`s id.

My questions are...
1. Why in the thread`s constructor the currentThreadID is main thread`s id after moveToThread(this). ( i read that QThread`s object lives in the thread which is calling it so i assume it`s normal showing the main thread`s ID but am i doing it right?)
2. Why the destructor of the QThread is not called (i recall a time when i saw it running before i fiddle with the QTimer`s stuff). The thread is closing because i watch it with OllyDbg but i still don`t understand the process.
3. Is it ok to use Qt::DirectConnection in this:


connect(serverSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(errorSlot(QAbstractSocket::SocketError)), Qt::DirectConnection);
connect(serverSocket, SIGNAL(disconnected()), this, SLOT(connectionClosed()), Qt::DirectConnection);
connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readData()), Qt::DirectConnection);
connect(serverSocket, SIGNAL(sslErrors(const QList<QSslError>&)), this, SLOT(sslErrors(const QList<QSslError>&)), Qt::DirectConnection);
connect(serverSocket, SIGNAL(encrypted()), this, SLOT(ready()), Qt::DirectConnection);

because IF i don`t i have to use qRegisterMetaType for the types in the SLOT() and i`m getting really weird random crashes.

Here some code:

SSLServer.cpp



#include "SSLserver.h"

SSLServer::SSLServer(quint16 port, QObject* parent)
: QTcpServer(parent)
{
if(!listen(QHostAddress::Any, port))
{
QMessageBox::critical(0, "Error!", tr("Server cannot listen at port %1!").arg(port), QMessageBox::Ok);
exit(5);
}
}

void SSLServer::incomingConnection(int socketDescriptor)
{
qDebug() << "OPening new Thread from sslserver TID: " << QThread::currentThreadId();// SHOW MAIN THREAD ID
thread = new SSLThread(socketDescriptor, 0);// HERE OPEN NEW THREAD WITH PARENT 0
connect(thread, SIGNAL(finished()), this, SLOT(fin()));
connect(thread, SIGNAL(messageToGui(QString)), QObject::parent(), SLOT(writeToLogs(QString)));
connect(thread, SIGNAL(addRegisteredUser(QString)), QObject::parent(), SLOT(addUserToList(QString)));
connect(thread, SIGNAL(delRegisteredUser(QString)), QObject::parent(), SLOT(removeUserFromList(QString)));
thread->start();
}

void SSLServer::fin()
{
qDebug() << "Closing Thread ID (from sslserver): " << thread->currentThreadId();// HERE SHOWS MAIN THREAD ID
thread->deleteLater();
}

SSLThread.cpp



#include "SSLthread.h"
#include <QtNetwork>

SSLThread::SSLThread(int socketDr, QObject* parent) : QThread(parent)
{
moveToThread( this );
socketDescriptor = socketDr;
.....
qDebug() << "ThreadID from constructor: " << currentThreadId();//SHOWS MAIN THREAD ID ??????
}

SSLThread::~SSLThread()
{
qDebug() << ">>>Destructor<<<";
//NEVER CALLED
}

void SSLThread::run()
{
qDebug() << "ThreadID: " << currentThreadId();//SHOWS NEW THREAD ID
serverSocket = new QSslSocket();
serverSocket->setProtocol(QSsl::AnyProtocol);
serverSocket->setPeerVerifyMode(QSslSocket::VerifyNone);
serverSocket->setDefaultCiphers(serverSocket->supportedCiphers());
connect(serverSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(errorSlot(QAbstractSocket::SocketError)), Qt::DirectConnection);
connect(serverSocket, SIGNAL(disconnected()), this, SLOT(connectionClosed()), Qt::DirectConnection);
connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readData()), Qt::DirectConnection);
connect(serverSocket, SIGNAL(sslErrors(const QList<QSslError>&)), this, SLOT(sslErrors(const QList<QSslError>&)), Qt::DirectConnection);
connect(serverSocket, SIGNAL(encrypted()), this, SLOT(ready()), Qt::DirectConnection);
//connect(serverSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)) , this, SLOT(stateChanged(QAbstractSocket::SocketState)), Qt::DirectConnection);
connect(serverSocket, SIGNAL(modeChanged(QSslSocket::SslMode)), this, SLOT(sslModeChanged(QSslSocket::SslMode)), Qt::DirectConnection);
timerTimeout = new QTimer(this);timerTimeout->setSingleShot(true);
connect(timerTimeout, SIGNAL(timeout()), this, SLOT(timeOut()));


.....(reading certificates and running stuff)
exec();
}

void SSLThread::connectionClosed()
{
qDebug() << "ThreadID: " << currentThreadId();
QSqlDatabase db = QSqlDatabase::database(uid);
if (db.isOpen())
db.close();
if (serverSocket->state() == QAbstractSocket::ClosingState)
{
connect(serverSocket, SIGNAL(disconnected()), SLOT(deleteLater()));
}
else
{
serverSocket->deleteLater();
}
emit delRegisteredUser(authUserName);
emit messageToGui(tr("%1 %2 quits the system.").arg(QTime::currentTime().toString()).arg(authUse rName));
authUserName.clear();
if(timerTimeout)
timerTimeout->deleteLater();
qDebug("Connection closed.");
exit(0);
}

void SSLThread::timeOut()
{
if(timerTimeout->isActive())
timerTimeout->stop();

serverSocket->close();
qDebug() << "ThreadID: " << currentThreadId();
}


Now the server is running fine.. it accepts connections, reads all the data, disconnects the clients fine... but i`m worried if i`m doing things properly. Also i`m worried if everything is cleaned properly... it`s important because that server should be 24/7 and memory leaks are not very welcome. Thank you in advance!

sadjoker
23rd April 2010, 13:23
Changing


connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

into SSLServer.cpp fixed a bug with not executing the timers of the next threads.