并发访问QTcpSocket对象

时间:2014-10-13 13:27:56

标签: c++ multithreading qt qthread qtcpsocket

我创建了一个继承自QThread的类,以便让一个线程与QTcpSocket对象一起运行。当此线程启动时,它将连接到服务器:如果连接被拒绝或连接丢失,则线程会尝试重新连接到服务器,尝试重新连接无限次。换句话说,此线程尝试保持与指定服务器的连接。

QTcpSocket*被声明为我班级的属性成员_socketrun()函数的第一行实例化_socket对象并尝试连接到服务器。 run()函数的最后一行调用_socket->disconnectFromHost()。我注册了_socket对象已断开连接的事件,以便呼叫_socket->deleteLater()

我创建的这个帖子工作正常。 现在我要添加一个函数来向服务器发送数据:这个函数应该调用write()对象的_socket函数,它应该被另一个线程调用。那么,我应该使用互斥锁来使用_socket对象吗?

2 个答案:

答案 0 :(得分:1)

  

一个继承自QThread

的类

首先解决这个问题。这里有很多人会告诉你You're Doing it Wrong!

QThread,更多的是线程控制器而不是线程,所以除非你想改变Qt管理线程的方式,否则我建议你不要继承它。相反,请按照How to Really, Truly Use QThread

中所述的方法进行操作

我将假设您有充分的理由在单独的线程中使用QTCpSocket,即使它是异步的。

如果你在另一个线程上有一个QTcpSocket并且想要调用套接字的write函数,你应该使用signal / slot机制,而不是直接从另一个线程调用该对象的函数。

因此,总结一下,在阅读了excellent article如何使用QThread之后,重构代码以创建一个从QObject派生的单独对象,该对象可以移动到新线程。然后使用信号/插槽机制将数据发送到该对象,然后可以调用套接字的写入函数。

答案 1 :(得分:0)

如果我理解正确,您希望从主线程向您的工作线程发送和接收信号。 documentation解释了如何做到这一点非常好:

class Worker : public QObject
{
    Q_OBJECT

public slots:
    void doWork(const QString &parameter) {
        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 QThreadexec()执行更改move的操作并向其发送/接收信号。{/ p>

在这种情况下,没有必要,也不建议继承run()。但是如果你这样做,不要忘记在Bradley Hughes成员函数中调用QThread::run(),以便线程启动它自己的事件循环(以便它可以处理异步操作)。

所以不,你的操作不需要互斥锁。主线程和工作线程的事件循环可以很好地进行通信,相互发送信号并进行同步。

我建议查看这个affinity解决方案,该解决方案同步2个线程,这是#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" 在2006年{{1}}未默认启动事件循环时创建的。这是他的例子的更新版本:

{{1}}

阅读Consume/Producer了解详情。