QT——C++ 多线程05

2023-11-17

一、创建多线程的方式

QT创建(使用)多线程的方式有三种。

  1. 直接创建QThread 对象,重写run方法,最后调用start方法启动线程。
  2. 通过调用QObject类提供的moveToThread方法实现
  3. 线程池

(一)方式一:

如果需要向run传入参数,或者返回执行结果,可以通过信号和槽机制实现

  • mywork.h
#ifndef MYWORK_H
#define MYWORK_H

#include <QObject>
#include <QThread>

/**
 *    @class   mywork.h
 *
 *    @brief   工作线程
 *
 *
 *    @author:   lihua
 *    @date:     2022-10-25  15:53
 */
class MyWork : public QThread
{
    Q_OBJECT
public:
    explicit MyWork(QThread *parent = nullptr);

signals:
    //信号由子线程发出,主线程接收(子线程返回执行结果给主线程)
    void signalWork(int result);

public slots:
    //信号由主线程发出,子线程接收(主线程传入参数给子线程)
    void slotWork(int num);

    // QThread interface
protected:
    void run();

private:
    int num = 0;

};

#endif // MYWORK_H

  • mywork.cpp
#include "mywork.h"
#include <QDebug>

MyWork::MyWork(QThread *parent) : QThread(parent)
{

}

void MyWork::slotWork(int num)
{
    //调用槽函数
    qDebug()<< "子线程的槽函数被调用"<<num;
    this->num = num;

}

/**
 * @brief 主线程传一个初始值num给子线程,子线程在num的基础上加100
 *
 * @param  run没有参数,num是通过槽函数获取的
 *
 * @return  run没有返回值将计算结果通过槽函数返回给主线程
 */
void MyWork::run()
{

    qDebug()<< "运行子线程<<" << QThread::currentThread();

    //主线程给一个初始值num
    int num = this->num;



    int result = num +100;

    //发出信号,订阅了此信号的订阅者的槽函数会被回调,将计算结果通过槽函数返回给主线程
    qDebug()<< "结果:"<<result;
    emit signalWork(result);


}

  • mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "mywork.h"

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    //子线程
    MyWork *thread;

    // 计算结果
    int result;

signals:
    //信号
    void signalMain(int num);

public slots:
    //槽函数
    void slotMain(int result);

};



#endif // MAINWINDOW_H

  • mainwindow.cpp
#include "mainwindow.h"
#include "mywork.h"
#include "ui_mainwindow.h"

#include <QThread>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    qDebug()<< QThread::currentThread();

    thread = new MyWork();


    //订阅signalMain信号,并指定回调函数。
    connect(this,&MainWindow::signalMain,thread,&MyWork::slotWork);

    //订阅signalWork信号,并指定回调函数
    //connect(thread,&MyWork::signalWork,this,&MainWindow::slotMain); 也可以用lamda实现
    connect(thread,&MyWork::signalWork,this,[=](int result){

        this->result = result;
        qDebug()<< "result="<<this->result;
    });

    //发出一个信号,将10通过槽函数slotWork传递给run
    emit signalMain(10);

    thread->start();


}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::slotMain(int result)
{
    this->result = result;

    qDebug()<< "result="<<this->result;
}

(二)方式二:

更改此对象及其子对象的线程关联。如果对象具有父对象,则无法移动该对象。事件处理将在targetThread中继续。
如果targetThread为零,则此对象及其子对象的所有事件处理都将停止。

请注意,对象的所有活动计时器都将重置。计时器首先在当前线程中停止,然后在targetThread中重新启动(以相同的间隔)。因此,在线程之间不断移动对象会无限期地延迟计时器事件。

在更改线程关联之前,QEvent::ThreadChange事件被发送到此对象。您可以处理此事件以执行任何特殊处理。请注意,任何发布到此对象的新事件都将在targetThread中处理。

警告:此函数不是线程安全的;当前线程必须与当前线程关联性相同。换句话说,此函数只能将对象从当前线程“推”到另一个线程,不能将对象从任意线程“拉”到当前线程

  • mywork1.h
#ifndef MYWORK1_H
#define MYWORK1_H

#include <QObject>

class MyWork1 : public QObject
{
    Q_OBJECT
public:
    explicit MyWork1(QObject *parent = nullptr);

    //工作函数
    void work();
signals:
    void curNumber(int  num);

public slots:
};

#endif // MYWORK1_H

  • mywork1.cpp
#include "mywork1.h"

#include <QThread>
#include <QDebug>

MyWork1::MyWork1(QObject *parent) : QObject(parent)
{

}

void MyWork1::work()
{
    qDebug()<< "子线程对象地址:"<<QThread::currentThread() ;

    int num = 0;
        while(1)
        {
            emit curNumber(num++);
            if(num == 1000)
            {
                break;
            }
            QThread::usleep(1);
        }
        qDebug() << "run() 执行完毕, 子线程退出...";
}

  • 核心代码
void MainWindow::testThread()
{
    QThread *thread = new QThread();

    MyWork1 *work = new MyWork1();

    //注意这个方法是QObject提供的,将对象从当前线程“推”到另一个线程运行
    work->moveToThread(thread);
    thread->start();

    //不能直接调用,直接调用还是主线程运行
    //work->work();
    //通过槽机制运行才能将对象交给targetThread运行。
    connect(ui->pushButton,&QPushButton::clicked,work, &MyWork1::work);

    connect(work,&MyWork1::curNumber,this,[=](int num){
        ui->textBrowser->setText(QString::number(num));
    });
}

(三)方式三:

QThreadPool类管理QThreads的集合。
QThreadPool管理和重新设计单个QThread对象,以帮助减少使用线程的程序中的线程创建成本。每个Qt应用程序都有一个全局QThreadPool对象,可以通过调用globalInstance()来访问该对象。
要使用QThreadPool线程之一,请将QRunnable子类化并实现run()虚拟函数。然后创建该类的对象并将其传递给QThreadPool::start()

#include "mywork2.h"
#include <QDebug>
#include <QThread>
MyWork2::MyWork2()
{

}

void MyWork2::run()
{
    qDebug()<< "线程池方式使用多线程。"<<QThread::currentThread();

}

/**
 * @brief 线程池测试
 *
 * @param
 * @param
 *
 * @return
 */
void MainWindow::testThreadPool()
{
    //获取线程池,同时设置最大线程数。
    QThreadPool::globalInstance()->setMaxThreadCount(2);
    MyWork2 *work = new MyWork2();

    QThreadPool::globalInstance()->start(work);
    
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QT——C++ 多线程05 的相关文章

  • 如何在列表框项目之间画一条线

    我希望能够用水平线分隔列表框中的每个项目 这只是我用于绘制项目的一些代码 private void symptomsList DrawItem object sender System Windows Forms DrawItemEvent
  • 实时服务器上的 woff 字体 MIME 类型错误

    我有一个 asp net MVC 4 网站 我在其中使用 woff 字体 在 VS IIS 上运行时一切正常 然而 当我将 pate 上传到 1and1 托管 实时服务器 时 我得到以下信息 网络错误 404 未找到 http www co
  • Newtonsoft JSON PreserveReferences处理自定义等于用法

    我目前在使用 Newtonsoft Json 时遇到一些问题 我想要的很简单 将要序列化的对象与所有属性和子属性进行比较以确保相等 我现在尝试创建自己的 EqualityComparer 但它仅与父对象的属性进行比较 另外 我尝试编写自己的
  • WPF 中的调度程序和异步等待

    我正在尝试学习 WPF C 中的异步编程 但我陷入了异步编程和使用调度程序的困境 它们是不同的还是在相同的场景中使用 我愿意简短地回答这个问题 以免含糊不清 因为我知道我混淆了 WPF 中的概念和函数 但还不足以在功能上正确使用它 我在这里
  • 指针问题(仅在发布版本中)

    不确定如何描述这一点 但我在这里 由于某种原因 当尝试创建我的游戏的发布版本进行测试时 它的敌人创建方面不起作用 Enemies e level1 3 e level1 0 Enemies sdlLib 500 2 3 128 250 32
  • 在高 dpi Windows 平台上自动重新缩放应用程序?

    我正在编写一个需要在高 dpi Windows 192dpi 而不是 96dpi 上运行的 Qt 应用程序 不幸的是 Qt 框架尚不支持高 dpi 至少在 Windows 上 因此我的应用程序及其所有元素看起来只有应有尺寸的一半 有没有办法
  • 如果使用 SingleOrDefault() 并在数字列表中搜索不在列表中的数字,如何返回 null?

    使用查询正数列表时SingleOrDefault 当在列表中找不到数字时 如何返回 null 或像 1 这样的自定义值 而不是类型的默认值 在本例中为 0 你可以使用 var first theIntegers Cast
  • WPF TabControl,用C#代码更改TabItem的背景颜色

    嗨 我认为这是一个初学者的问题 我搜索了所有相关问题 但所有这些都由 xaml 回答 但是 我需要的是后台代码 我有一个 TabControl 我需要设置其项目的背景颜色 我需要在选择 取消选择和悬停时为项目设置不同的颜色 非常感谢你的帮助
  • 在 ASP.NET Core 3.1 中使用包含“System.Web.HttpContext”的旧项目

    我们有一些用 Net Framework编写的遗留项目 应该由由ASP NET Core3 1编写的API项目使用 问题是这些遗留项目正在使用 System Web HttpContext 您知道它不再存在于 net core 中 现在我们
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • 实体框架 4 DB 优先依赖注入?

    我更喜欢创建自己的数据库 设置索引 唯一约束等 使用 edmx 实体框架设计器 从数据库生成域模型是轻而易举的事 现在我有兴趣使用依赖注入来设置一些存储库 我查看了 StackOverflow 上的一些文章和帖子 似乎重点关注代码优先方法
  • C++ 复制初始化和直接初始化,奇怪的情况

    在继续阅读本文之前 请阅读在 C 中 复制初始化和直接初始化之间有区别吗 https stackoverflow com questions 1051379 is there a difference in c between copy i
  • 在 Dynamics CRM 插件中访问电子邮件发件人地址

    我正在编写一个 Dynamics CRM 2011 插件 该插件挂钩到电子邮件实体的更新后事件 阶段 40 pipeline http msdn microsoft com en us library gg327941 aspx 并且在此阶
  • WCF:将随机数添加到 UsernameToken

    我正在尝试连接到用 Java 编写的 Web 服务 但有些东西我无法弄清楚 使用 WCF 和 customBinding 几乎一切似乎都很好 除了 SOAP 消息的一部分 因为它缺少 Nonce 和 Created 部分节点 显然我错过了一
  • 为什么 C# Math.Ceiling 向下舍入?

    我今天过得很艰难 但有些事情不太对劲 在我的 C 代码中 我有这样的内容 Math Ceiling decimal this TotalRecordCount this PageSize Where int TotalRecordCount
  • x86 上未对齐的指针

    有人可以提供一个示例 将指针从一种类型转换为另一种类型由于未对齐而失败吗 在评论中这个答案 https stackoverflow com questions 544928 reading integer size bytes from a
  • 如何使用 std::string 将所有出现的一个字符替换为两个字符?

    有没有一种简单的方法来替换所有出现的 in a std string with 转义 a 中的所有斜杠std string 完成此操作的最简单方法可能是boost字符串算法库 http www boost org doc libs 1 46
  • ASP.NET MVC 6 (ASP.NET 5) 中的 Application_PreSendRequestHeaders 和 Application_BeginRequest

    如何在 ASP NET 5 MVC6 中使用这些方法 在 MVC5 中 我在 Global asax 中使用了它 现在呢 也许是入门班 protected void Application PreSendRequestHeaders obj
  • 使用 libcurl 检查 SFTP 站点上是否存在文件

    我使用 C 和 libcurl 进行 SFTP FTPS 传输 在上传文件之前 我需要检查文件是否存在而不实际下载它 如果该文件不存在 我会遇到以下问题 set up curlhandle for the public private ke

随机推荐