QT基础篇(12)QT5多线程

这篇具有很好参考价值的文章主要介绍了QT基础篇(12)QT5多线程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在任何一门语言中,多线程都是一个相对其他方面比较重要的点,这里面的知识体系很庞大,同步和异步之间的处理方式,以及IO多路复用等等各种进行性能优化的方面,在往上层一点我们不可能一直进行系统层次的调用,这样太费时间也太麻烦,就到设计模式这里,比如反应器(Reactor)模式,再者多线程对代码的敏感程度较高,很对细微的改变可能会带来意向不到的效果,这更要求我们对于我们写的代码有更深次的理解,不仅仅是代码本身,还要求代码执行阶段锁遇到的各种问题,这就非常考验一个程序员的功底。

1.多线程及简单实例

QT5的多线程可以使用QtConcurrent和QThread两种方式来实现。

  1. 使用QtConcurrent: QtConcurrent提供了一种简单的方式来编写并行的代码。通过使用QtConcurrent::run()函数,可以在后台线程中执行一个函数。
#include <QtConcurrent>
#include <QDebug>

void myFunction()
{
    qDebug() << "Running in background thread";
}

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

    QtConcurrent::run(myFunction);

    qDebug() << "Running in main thread";

    return a.exec();
}
  1. 使用QThread: QThread类提供了一个线程对象,可以通过继承QThread来实现自定义的线程类。
#include <QThread>
#include <QDebug>

class MyThread : public QThread
{
public:
    void run() override
    {
        qDebug() << "Running in background thread";
    }
};

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

    MyThread thread;
    thread.start();

    qDebug() << "Running in main thread";

    return a.exec();
}

以上示例中,myFunction()函数或者MyThread类的run()函数会在后台线程中执行,而主线程会继续执行下面的代码。

需要注意的是,当使用QThread时,不要直接调用run()函数,而是通过start()函数来启动线程。另外,在多线程编程中,需要注意线程安全性和共享资源的竞争问题。

2.多线程控制
2.1互斥量

在QT中,可以使用QMutex(互斥量)来控制多个线程对共享资源进行互斥访问,以避免竞争条件和数据损坏。

下面是一个使用QMutex的简单示例:

#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QMutex>

QMutex mutex;

int sharedData = 0;

class MyThread : public QThread
{
public:
    void run() override
    {
        mutex.lock();
        
        // 访问共享资源
        for (int i = 0; i < 10000; i++) {
            sharedData++;
        }
        
        mutex.unlock();
    }
};

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

    MyThread thread1;
    MyThread thread2;

    thread1.start();
    thread2.start();

    thread1.wait();
    thread2.wait();

    qDebug() << "sharedData: " << sharedData;

    return a.exec();
}

在这个示例中,我们创建了两个线程来递增sharedData变量的值。为了确保对sharedData的访问是互斥的,我们使用了mutex对象。在run()函数中,我们使用mutex.lock()来锁定互斥量,然后执行对共享资源的访问,最后使用mutex.unlock()来解锁互斥量。

这样就保证了同时只有一个线程可以访问共享资源,避免了数据损坏。

2.2信号量

在QT中,可以使用QSemaphore(信号量)来控制多个线程对资源的访问。信号量允许指定一个资源的数量,线程可以通过获取和释放信号量来控制对资源的访问。

下面是一个使用QSemaphore的简单示例:

#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QSemaphore>

QSemaphore semaphore(1); // 初始化信号量为1

int sharedData = 0;

class MyThread : public QThread
{
public:
    void run() override
    {
        semaphore.acquire(); // 等待获取信号量

        // 访问共享资源
        for (int i = 0; i < 10000; i++) {
            sharedData++;
        }

        semaphore.release(); // 释放信号量
    }
};

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

    MyThread thread1;
    MyThread thread2;

    thread1.start();
    thread2.start();

    thread1.wait();
    thread2.wait();

    qDebug() << "sharedData: " << sharedData;

    return a.exec();
}

在这个示例中,我们创建了两个线程来递增sharedData变量的值。为了确保对sharedData的访问是互斥的,我们使用了一个信号量semaphore,并将其初始化为1。

在每个线程的run()函数中,我们首先使用semaphore.acquire()来等待获取信号量。一旦线程获取到信号量,它就可以访问共享资源,进行对sharedData的递增操作。最后,线程使用semaphore.release()来释放信号量。

由于我们将信号量初始化为1,所以只有一个线程能够获取到信号量,而另一个线程必须等待。这样就确保了对共享资源的访问是互斥的。

2.3线程等待及唤醒

在Qt中,可以使用QWaitCondition类来控制线程的等待和唤醒。QWaitCondition提供了一个条件变量,可以让线程在某个条件满足时等待,并在条件满足时被唤醒。

下面是一个使用QWaitCondition的简单示例:

#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QWaitCondition>
#include <QMutex>

QWaitCondition condition;
QMutex mutex;
bool ready = false;

class MyThread : public QThread
{
public:
    void run() override
    {
        mutex.lock();
        while (!ready) {
            condition.wait(&mutex);
        }
        mutex.unlock();

        qDebug() << "Thread " << QThread::currentThread() << " is running";
    }
};

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

    MyThread thread1;
    MyThread thread2;

    thread1.start();
    thread2.start();

    // 模拟一段耗时操作
    QThread::currentThread()->sleep(2);

    mutex.lock();
    ready = true;
    condition.wakeAll();
    mutex.unlock();

    thread1.wait();
    thread2.wait();

    return a.exec();
}

在这个示例中,我们创建了两个线程来执行一段耗时操作。在主线程中,我们首先将ready变量设置为true,然后调用condition.wakeAll()来唤醒所有等待在条件变量上的线程。

在每个线程的run()函数中,我们首先使用mutex.lock()来锁定互斥量。然后,线程进入一个循环,使用condition.wait(&mutex)来等待条件变量。只有当条件变量满足时,线程才会被唤醒。一旦被唤醒,线程会打印一条消息,并继续执行。

这样,我们就实现了一种控制线程等待和唤醒的机制。主线程通过设置条件变量并唤醒等待的线程,实现了线程的同步。

3.多线程应用
3.1服务器端编程

在Qt中,可以使用QTcpServer来实现多线程的服务器端编程。下面是一个简单的示例:

#include <QCoreApplication>
#include <QTcpServer>
#include <QTcpSocket>
#include <QThreadPool>
#include <QDebug>

class MyThread : public QThread
{
public:
    MyThread(qintptr socketDescriptor, QObject *parent = nullptr)
        : QThread(parent), m_socketDescriptor(socketDescriptor)
    {
    }

    void run() override
    {
        QTcpSocket socket;
        if (!socket.setSocketDescriptor(m_socketDescriptor))
        {
            emit error(socket.error());
            return;
        }

        qDebug() << "New connection:" << socket.peerAddress().toString() << ":" << socket.peerPort();

        // 处理客户端请求
        QByteArray requestData = socket.readAll();
        qDebug() << "Received data:" << requestData;

        // 响应客户端请求
        QByteArray responseData = "Hello from server!";
        socket.write(responseData);
        socket.waitForBytesWritten();

        // 断开连接
        socket.disconnectFromHost();
        socket.waitForDisconnected();

        qDebug() << "Connection closed:" << socket.peerAddress().toString() << ":" << socket.peerPort();
    }

signals:
    void error(QAbstractSocket::SocketError socketError);

private:
    qintptr m_socketDescriptor;
};

class MyServer : public QTcpServer
{
    Q_OBJECT
public:
    MyServer(QObject *parent = nullptr)
        : QTcpServer(parent)
    {
    }

protected:
    void incomingConnection(qintptr socketDescriptor) override
    {
        MyThread *thread = new MyThread(socketDescriptor, this);
        connect(thread, &MyThread::finished, thread, &MyThread::deleteLater);
        connect(thread, &MyThread::error, this, &MyServer::handleError);
        thread->start();
    }

private slots:
    void handleError(QAbstractSocket::SocketError socketError)
    {
        qDebug() << "Socket error:" << socketError;
    }
};

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

    MyServer server;
    if (!server.listen(QHostAddress::Any, 1234))
    {
        qDebug() << "Failed to start server!";
        return -1;
    }

    qDebug() << "Server started, listening on port 1234...";

    return a.exec();
}

#include "main.moc"

在这个示例中,我们创建了一个MyServer类,继承自QTcpServer。在incomingConnection()函数中,每次有新的连接到来时,我们创建一个新的MyThread线程来处理该连接。

MyThread类继承自QThread,覆盖了run()函数。在run()函数中,我们创建了一个QTcpSocket对象,并使用setSocketDescriptor()函数将其与传入的套接字描述符关联起来。然后,我们处理客户端的请求,读取请求数据,对数据进行处理,并向客户端返回响应数据。最后,断开连接。

在main()函数中,我们创建了一个MyServer对象,并通过调用listen()函数来启动服务器。通过传入监听的IP地址和端口号,来监听对应的地址和端口。如果listen()成功启动服务器,则会在控制台显示对应的提示信息。

这样,我们就实现了一个多线程的服务器端程序。每次有新的连接到来时,都会创建一个新的线程来处理该连接,实现了服务器的并发处理能力。

3.2客户端编程

在Qt中,可以使用QThread来实现多线程的客户端编程。下面是一个简单的示例:

#include <QCoreApplication>
#include <QTcpSocket>
#include <QDebug>
#include <QThread>

class MyThread : public QThread
{
public:
    MyThread(QObject *parent = nullptr)
        : QThread(parent)
    {
    }

    void run() override
    {
        QTcpSocket socket;
        socket.connectToHost("127.0.0.1", 1234);
        
        if(!socket.waitForConnected())
        {
            qDebug() << "Failed to connect to server!";
            return;
        }

        // 发送请求
        QByteArray requestData = "Hello from client!";
        socket.write(requestData);
        socket.waitForBytesWritten();

        // 接收响应
        QByteArray responseData = socket.readAll();
        qDebug() << "Received data: " << responseData;

        // 断开连接
        socket.disconnectFromHost();
        socket.waitForDisconnected();
    }
};

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

    MyThread thread;
    thread.start();

    return a.exec();
}

#include "main.moc"

在这个示例中,我们创建了一个MyThread类,继承自QThread。在run()函数中,我们创建了一个QTcpSocket对象,并使用connectToHost()函数连接到服务器端。如果连接成功,则发送请求数据,并等待响应数据的返回。最后,断开连接。

在main()函数中,我们创建了一个MyThread对象,并调用start()函数来启动线程。

这样,我们就实现了一个多线程的客户端程序。通过在独立的线程中与服务器建立连接、发送请求和接收响应,实现了客户端的并发操作能力。文章来源地址https://www.toymoban.com/news/detail-815546.html

到了这里,关于QT基础篇(12)QT5多线程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Qt5.12】Qt5.12安装教程[通俗易懂]

    Qt5.12下载网址: Index of /archive/qt/5.12/5.12.2 选择Windows平台, Linux和Mac平台类似 下载好之后的安装包: Step1: 双击安装包, 稍等片刻, 然后点击next Step2: 如果没有账号, 则选择skip Step3: Qt设置欢迎界面, 选择下一步 Step4: 选择安装路径 Step5: 选择组件, 然后选择下一步 Step6: 同意许可协议

    2024年02月13日
    浏览(44)
  • 【Qt】Qt5.12.12安装教程详解

    Qt(官方发音 [kju:t],音同 cute)是一个跨平台的 C++ 开发库,主要用来开发图形用户界面(Graphical User Interface,GUI)程序,当然也可以开发不带界面的命令行(Command User Interface,CUI)程序。 Qt 是纯 C++ 开发的,所以学好 C++ 非常有必要,对于不了解 C++ 的读者,我建议先阅读《

    2024年02月13日
    浏览(38)
  • 【Qt 学习之路】记一次安装 Qt5.12.12 安卓环境的失败案例

    安装的 Qt5.12.12 版本 Qt下载地址: https://download.qt.io/archive/qt/ 安装Qt,可能会碰到“qt.tool.perl”安装程序错误,可以看我的记录解决: Qt开发 之 安装程序错误–安装进程(qt.tool.perl)的解决办法 JDK NDK SDK openssl 注意组合套件的版本和Qt的版本要对应起来!同时,安装路径不可

    2024年02月19日
    浏览(33)
  • Qt5.14.2 Qt多线程实战演练,全面掌握线程同步和线程池最佳实践

    多线程编程是每个开发者必须掌握的基本能力之一。在上一篇文章中,我们学习了Qt多线程编程的理论知识。本文将切入实战,提供多个案例代码,帮助你彻底掌握Qt的多线程编程实践技巧。 案例1: 使用QThread执行耗时任务 这个案例演示了如何通过继承QThread和重写run()函数,在

    2024年03月20日
    浏览(39)
  • QT5.12在windows上边的安装

    使用国内镜像源在线安装QT(2023.3.25更新)_qt国内镜像_Iotfsd的博客-CSDN博客 先下载 STEP1:下载qt online installer Index of /official_releases/online_installers (qt.io) STEP1:使用国内镜像源在线安装Qt     qDPass(12MB/s) 在《STEP1》下载的“qt-unified-windows-x64-4.5.2-online.exe”目录进入CMD,然后运行下面

    2024年02月12日
    浏览(33)
  • Qt5.12实战之正则与QregExp使用

    1.普通字符匹配: ab+ : 匹配一个a和任意个b 如: ab abb abbbbbb c : 匹配一个c 如 : abcde 匹配内容: c 匹配开始索引:2 匹配结束索引 3 bcd : 匹配字符串 bcd 如: abcde 匹配内容是: bcd 匹配开始索引是:1 匹配结束索引是:4 2.转换符匹配: :转义字符匹配 如: r n t \\\\ ^ $ . 匹配的内容分别是 回

    2024年02月06日
    浏览(37)
  • Ubuntu 下安装Qt5.12.12无法输入中文解决方法

    (1)VMware Workstation 15 Pro (2)Ubuntu 20.04 (3)Qt 5.12.12 64bits (4)Qt Creator 5.0.2 (5)已经安装了fcitx,google拼音和搜狗拼音。 安装完Qt 5.12.12后,打开Qt Creator,发现无法输入中文,并且点击Ubuntu左上角的键盘,也无法切换中文输入,Ubuntu已经安装了Fcitx。但是在其他的环境下是

    2024年02月11日
    浏览(44)
  • Ubuntu与致远ARM交叉编译Qt5.12环境

            ARM板现有环境配置(主要是对/etc/profile/编辑)较简单,参考上一篇博客,板子上已经部署了Qt5.15。 Ubuntu与国产致远ARM_3568交叉编译Qt 此文档只是为了记录错误的过程,下一往篇博客会直接介绍正确的配置。 https://blog.csdn.net/qq_35529025/article/details/129524412        

    2024年02月22日
    浏览(42)
  • Qt5.12实战之使用QLabel控件显示图像与动画

    演示效果: 显示图像前先添加资源到qrc 直接复制到res目录 然后添加已存在目录 直接显示图像 加载图像成功后显示 显示gif动画 显示超链接

    2024年01月18日
    浏览(39)
  • Qt5.12安装教程+组件选择MinGW+开源协议LGPL

    今天重装了一下QT,发现以前忽略的点,mark一下。 安装QT或者平时新建项目的时候,常常碰到组件选择界面,让人头疼。找到别人整理的文档,为了自己以后搞清楚,摘自https://www.cnblogs.com/lixuejian/p/10903088.html 如下图所示,安装Qt时有选择组件这一步,全部安装未免太占磁盘控

    2024年02月15日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包