QTcpSocket 在子线程执行测试笔记

本文是在子线程成创建QTcpSocke对象,并且向本地服务端在不同时刻发送不同指令。网上教程有很多,但发现大多数开启子线程的方式都是子类化QThread,然后在run()函数中写入需要执行的代码,但有篇博客强烈批评了该做法,主要原因请看以下两篇博客。

#include <QtCore>
#include <QTcpSocket>
class Worker : public QObject
{
    Q_OBJECT
public:
    ~Worker()
    {
        if(tcp!=nullptr)
        {
            delete tcp;
        }
    }
private:
    QTcpSocket *tcp;
    //int i;
public:
    void foo()
    {
        qDebug()<<"Worker::Test get called from?: "<<QThread::currentThreadId();
    }

public slots:
    void Connect()
    {
        tcp = new QTcpSocket;
        tcp->connectToHost("127.0.0.1",110);
        tcp->waitForConnected();
    }

    void onSend1()
    {
        tcp->write("Hello");
        tcp->waitForBytesWritten();      
        //子线程ID号  
        qDebug()<<"Worker::Send get called from?: "<<QThread::currentThreadId();
    }

    void onSend2()
    {
        tcp->write("Qt");
        tcp->waitForBytesWritten();
        //子线程ID号
        qDebug()<<"Worker::Send get called from?: "<<QThread::currentThreadId();
    }
};

定义一个Dummy类用于与出现子线程:

class Dummy:public QObject
{
    Q_OBJECT
signals:
    void sendConnect();
public:
    void Connect()
    {
        emit sendConnect();
    }
};

主函数:

#include "main.moc"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //主线程Id号
    qDebug()<<"From main thread: "<<QThread::currentThreadId();

    QThread t;
    QTimer timer;
    QTimer timer2;
    Worker worker;
    Dummy dm;

    QObject::connect(&dm,SIGNAL(sendConnect()),&worker,SLOT(Connect()));
    QObject::connect(&timer, SIGNAL(timeout()), &worker, SLOT(onSend1()));
    QObject::connect(&timer2,SIGNAL(timeout()),&worker,SLOT(onSend2()));

    //关键一步
    worker.moveToThread(&t);



    //线程开启
    t.start();

    //向worker 发送连接请求             
    dm.Connect();

    //猜猜下面这个函数在哪个线程执行?
    dm.foo();

    timer.start(1000);
    timer2.start(1000);
    return a.exec();
}

在此需要注意一点,对象内定义的成员变量是属于定义该对象的线程的,意思是Worker是在main()定义,那么Worker中定义的成员变量是属于主线程的,在其他slot函数中使用是属于跨线程使用。因此,如果在Worker的构造函数中对QTcpSocket进行实例化,那么执行上述方式的话,就会出现以下错误:

 QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpSocket(0x111ba20), parent's thread is QThread(0x11117f0), current thread is QThread(0x68fe68)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpSocket(0x111ba20), parent's thread is QThread(0x11117f0), current thread is QThread(0x68fe68)

错误实例化成员变量

所以在Conntect() 在对QTcpSocket进行了实例化,并通过Workder的析构函数回收其内存,防止内存泄漏。

正确运行结果如下图所示:
正确运行结果

从结果可以看到,Dummy::foo() 实际上是在主线程执行的,而通过信号/槽机制调用的Dummy的slot函数是在子线程中执行的。

个人总结

接触Qt时间很短,信号/槽机制、以及事件并不是特别熟悉,既然这个方式是正确的,就先学着吧。而这个方法可以看做是QThread对象开启了一个线程,然后可以将QObject的子类对象放进这个线程中,如果需要调用QObject子类对象的函数,需要通过信号/槽机制来实现。

  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
可能是因为在子线程中进行了UI操作,导致程序崩溃。Qt建议在主线程中处理UI事件,而不是在子线程中操作UI。你可以使用信号槽机制来实现线程和主线程之间的通信,从而避免这个问题。具体做法是: 1. 在子线程中创建socket连接。 2. 定义一个信号,当socket连接成功时发出该信号。 3. 在主线程中连接该信号,并在其槽函数中执行UI操作。 示例代码如下: ```cpp // 线程 void Thread::run() { QTcpSocket *socket = new QTcpSocket; socket->connectToHost("127.0.0.1", 1234); if (socket->waitForConnected()) { // 连接成功,发出信号 emit connected(); } else { // 连接失败,发出错误信号 emit error(socket->errorString()); } } // 主线程 void MainWindow::onConnect() { Thread *thread = new Thread; connect(thread, &Thread::connected, this, &MainWindow::onConnected); connect(thread, &Thread::error, this, &MainWindow::onError); thread->start(); } void MainWindow::onConnected() { // 执行UI操作 ui->statusBar->showMessage("Connected"); } void MainWindow::onError(const QString &error) { // 显示错误信息 QMessageBox::critical(this, "Error", error); } ``` 在这个例中,当用户点击“连接”按钮时,会创建一个新的线程,在该线程中连接socket。当连接成功时,会发出`connected`信号,该信号与主线程中的`onConnected`槽函数连接,以执行UI操作。如果连接失败,则会发出`error`信号,该信号与主线程中的`onError`槽函数连接,以显示错误信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值