Параллельный доступ к объекту QTcpSocket
Я создал класс, который наследует от QThread
чтобы иметь поток, работающий с QTcpSocket
объект. Когда этот поток запускается, он подключается к серверу: если в соединении отказано или соединение потеряно, поток пытается повторно подключиться к серверу, пытаясь восстановить соединение неограниченное количество раз. Другими словами, этот поток пытается сохранить соединение с указанным сервером.
QTcpSocket*
объявлен как член атрибута _socket
моего класса. Первая строка run()
функция создает экземпляр _socket
объект и пытается подключиться к серверу. Последняя строка run()
вызовы функций _socket->disconnectFromHost()
, Я зарегистрировал событие, отключенное от _socket
объект, чтобы позвонить _socket->deleteLater()
,
Эта тема, которую я создал, работает правильно. Теперь я бы добавил функцию для отправки данных на сервер: эта функция должна вызывать write()
функция _socket
объект, и он должен быть вызван другим потоком. Итак, я должен использовать мьютекс, чтобы использовать _socket
объект?
2 ответа
класс, который наследуется от QThread
Начните с решения этого в первую очередь. Многие люди здесь скажут вам, что вы делаете это неправильно!
QThread - это скорее контроллер потоков, чем поток, поэтому, если вы не хотите изменить способ управления потоками в Qt, я рекомендую вам не наследовать его. Вместо этого следуйте методу, описанному в разделе Как на самом деле использовать QThread.
Я собираюсь предположить, что у вас есть хорошая причина использовать QTCpSocket в отдельном потоке, даже если он асинхронный.
Если у вас есть QTcpSocket в другом потоке и вы хотите вызвать функцию записи сокета, вы должны использовать механизм сигнал / слот, а не вызывать функцию объекта напрямую из другого потока.
Итак, подведя итог, прочитав отличную статью о том, как использовать QThread, проведите рефакторинг вашего кода, чтобы создать отдельный объект, производный от QObject, который можно переместить в новый поток. Затем используйте механизм сигнал / слот для отправки данных этому объекту, который затем может вызвать функцию записи сокета.
Если я правильно понял, вы хотите отправлять и получать сигналы из основного потока в ваш рабочий поток. Документация довольно хорошо объясняет, как это сделать:
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 &);
};
Вы должны создать QObject
в нем будет функция-член, выполняющая операции, которые вы хотите выполнять в отдельном потоке. Вы двигаете это QObject
к QThread
Вы хотите выполнить операцию по изменению ее аффинности и отправлять / получать сигналы от нее.
В таких случаях нет необходимости и не рекомендуется наследовать QThread
, Но если вы это сделаете, не забудьте позвонить exec()
в run()
функция-член, чтобы поток запускал свой собственный цикл событий (чтобы он мог обрабатывать асинхронные операции).
Так что нет, вам не нужны мьютексы для ваших операций. Циклы событий основного потока и рабочего потока могут красиво общаться, посылать сигналы друг другу и синхронизироваться.
Я рекомендую взглянуть на это решение Consume/Producer, которое синхронизирует 2 потока и которое было создано Bradley Hughes
еще в 2006 году, когда QThread::run()
не запускал цикл событий по умолчанию. Вот обновленная версия его примера:
#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"
Читайте здесь для получения дополнительной информации.