Reputation: 8310
I created a class that inherits from QThread
in order to have a thread running with a QTcpSocket
object. When this thread starts, it connects to a server: if the connection is refused or if the connection is lost, the thread tries to reconnect to the server, trying to reconnect for an indefinite number of times. In other words, this thread tries to keep the connection with the specified server.
A QTcpSocket*
is declared as the attribute member _socket
of my class. The first line of the run()
function instantiates the _socket
object and tries to connect to the server. The last line of the run()
function calls _socket->disconnectFromHost()
. I registered the event disconnected of the _socket
object, in order to call _socket->deleteLater()
.
This thread that I created is working properly.
Now I would add a function in order to send data to the server: this function should call the write()
function of the _socket
object and it should be invoked by another thread. So, should I use a mutex in order to use the _socket
object?
Upvotes: 0
Views: 432
Reputation: 4091
If I understood correctly you want to send and receive signals from the main thread to your worker thread. The documentation explains pretty good how to do this:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
You must create a QObject
that will have a member function doing the operations you want to have in your separate thread. You move this QObject
to the QThread
you want to execute the operation in changing its affinity and send/receive signals to/from it.
In cases like these it is not necessary and not recommended to inherit QThread
. But if you do so, don't forget to call exec()
in the run()
member function so that the thread starts its own event loop(so that it can handle asynchronous operations).
So no, you don't need mutexes for your operations. The event loops of the main thread and worker thread can beautifully communicate, send signals to each other and synchronize.
I recommend looking at this Consume/Producer solution which synchronizes 2 threads and which was created by Bradley Hughes
back in 2006 when QThread::run()
wasn't starting the event loop by default. Here is an updated version of his example:
#include <QtCore>
#include <stdio.h>
enum {
Limit = 123456,
BlockSize = 7890
};
class Producer : public QObject
{
Q_OBJECT
QByteArray data;
int bytes;
public:
inline Producer() : bytes(0) { }
public slots:
void produce()
{
int remaining = Limit - bytes;
if (remaining == 0) {
emit finished();
return;
}
// this will never happen
if (data.size() != 0)
qFatal("Producer: Consumer failed to consume!");
int size = qMin(int(BlockSize), remaining);
bytes += size;
remaining -= size;
data.fill('Q', size);
printf("Producer: produced %d more bytes, %d of %d total\n", size, bytes, Limit);
emit produced(&data);
}
signals:
void produced(QByteArray *data);
void finished();
};
class Consumer : public QObject
{
Q_OBJECT
int bytes;
public:
inline Consumer() : bytes(0) { }
public slots:
void consume(QByteArray *data)
{
// this will never happen
if (data->size() == 0)
qFatal("Consumer: Producer failed to produce!");
int remaining = Limit - bytes;
int size = data->size();
remaining -= size;
bytes += size;
data->clear();
printf("Consumer: consumed %d more bytes, %d of %d total\n", size, bytes, Limit);
emit consumed();
if (remaining == 0)
emit finished();
}
signals:
void consumed();
void finished();
};
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
// create the producer and consumer and plug them together
Producer producer;
Consumer consumer;
producer.connect(&consumer,
SIGNAL(consumed()),
SLOT(produce()));
consumer.connect(&producer,
SIGNAL(produced(QByteArray *)),
SLOT(consume(QByteArray *)));
// they both get their own thread
QThread producerThread;
producer.moveToThread(&producerThread);
QThread consumerThread;
consumer.moveToThread(&consumerThread);
// start producing once the producer's thread has started
producer.connect(&producerThread,
SIGNAL(started()),
SLOT(produce()));
// when the consumer is done, it stops its thread
consumerThread.connect(&consumer,
SIGNAL(finished()),
SLOT(quit()));
// when consumerThread is done, it stops the producerThread
producerThread.connect(&consumerThread,
SIGNAL(finished()),
SLOT(quit()));
// when producerThread is done, it quits the application
app.connect(&producerThread,
SIGNAL(finished()),
SLOT(quit()));
// go!
producerThread.start();
consumerThread.start();
return app.exec();
}
#include "main.moc"
Read here for more info.
Upvotes: 0
Reputation: 27611
a class that inherits from QThread
Begin by addressing this first. Many people here will tell you that You're Doing it Wrong!
QThread, is more of a thread controller than a thread, so unless you want to change how Qt is going to manage threads, I recommend that you don't inherit from it. Instead, follow the method as described in How to Really, Truly Use QThread.
I'm going to assume that you've a good reason to use the QTCpSocket in a separate thread, even though it's asynchronous.
If you have a QTcpSocket on a different thread and want to call the socket's write function, you should be using the signal / slot mechanism, rather than calling the object's function directly from a different thread.
So, to summarise, following reading the excellent article of how to use QThread, refactor your code to create a separate object, derived from QObject, which can be moved to a new thread. Then use the signal / slot mechanism to send data to that object, which can then call the socket's write function.
Upvotes: 1