首页 > 编程语言 >Qt多线程- QThread 创建多线程程序

Qt多线程- QThread 创建多线程程序

时间:2024-11-05 21:16:44浏览次数:3  
标签:run Qt void 线程 Dialog ui 多线程 QThread 函数

QThread 创建多线程程序

QThread 类功能简介

今天说一下 Qt 中的多线程。QThread 类不依赖平台的管理线程的方法。一个 QThread 类的对象管理一个线程,一般从 QThread 继承一个自定义类,并重新定义虚函数 run(),在 run() 函数里实现线程需要完成的任务。

将应用程序的线程称为主线程,额外创建的线程称为工作线程。一般在主线程里创建工作线程,并调用 start() 开始执行工作线程的任务。start() 会在内部调用 run() 函数,进入工作线程的事件循环,在 run() 函数里调用 exit()quit() 可以结束线程的事件循环,或在主线程调用 terminate() 强制结束线程。

QThread 类的主要接口函数、信号和槽函数如下:

类型函数功能
公共函数bool isFinished ()线程是否结束
bool isRunning ()线程是否正在运行
Priority priority ()返回线程的优先级
公共函数void setPriority (Priority priority)设置线程优先级
void exit (int returnCode = 0)退出线程的事件循环,退出代码为 returnCode 0 表示成功,否则表示有错误。
bool wait (unsigned long time)阻止线程执行,知道线程结束,或等待时间超过时间
公共槽函数void quit ()退出线程的事件循环,并返回代码 0,等效 exit (0)
void start (priority priority)内部调用 run() 开始执行线程,操作系统根据优先级参数调度
void terminate ()终止线程运行,但不立刻结束线程,二十等待操作系统结束线程。使用 terminate() 后要 wait()
信号void finished ()在线程就要结束的时候发射此信号
void started ()在线程开始执行、run() 函数被调用之前发射此信号
静态公共成员int idealThreadCount ()返回系统上能运行的线程的理想个数
void msleep (unsigned long msecs)强制当前线程休眠 msecs 毫秒
void sleep (unsigned long secs)强制当前线程休眠 secs
void usleep (unsigned long usecs)强制当前线程休眠 usecs 微妙
保护函数virtual void run ()start() 调用 run() 函数开始线程任务的执行,所以在 run() 函数里实现线程的任务功能
int exec ()run() 函数调用,进入线程的事件循环,等待 exit() 退出

QThreadQObject 的子类,所以可以使用信号与槽机制。QThread 自身定义了 started()finished() 俩个信号,started() 信号在线程开始执行之前发射,也就是在 run() 函数被调用之前,finished() 信号在线程就要结束的时候发射。

投骰子线程 QDiceThread

作为实例,定义一个投骰子的线程类 QDiceThread,类的声明部分如下:

class QDiceThread : public QThread
{
    Q_OBJECT
private:
    int     m_seq=0;//掷骰子次数序号
    int     m_diceValue;//骰子点数
    bool    m_Paused=true; //掷一次骰子
    bool    m_stop=false; //停止线程
protected:
    void    run() Q_DECL_OVERRIDE;  //线程任务
public:
    QDiceThread();

    void    diceBegin();//掷一次骰子
    void    dicePause();//暂停
    void    stopThread(); //结束线程
signals:
    void    newValue(int seq,int diceValue); //产生新点数的信号
};
  • 重载虚函数 run(),在此函数里完成线程的主要任务。
  • 自定义 diceBegin()dicePause()stopThread() 三个公共函数用于线程控制,这三个函数由主线程调用。
  • 定义了要给信号 newValue(int seq, int diceValue) 用于在投一次骰子得到新的点数之后发射此信号,由主线程的槽函数相应以获取值。

QDiceThread 类的实现代码如下:

#include "qdicethread.h"
#include    <QTime>

#include <QRandomGenerator>

QDiceThread::QDiceThread()
{

}

void QDiceThread::diceBegin()
{ //开始掷骰子
    m_Paused=false;
}

void QDiceThread::dicePause()
{//暂停掷骰子
    m_Paused=true;
}

void QDiceThread::stopThread()
{//停止线程
    m_stop=true;
}

void QDiceThread::run()
{//线程任务
    m_stop=false;   //启动线程时令m_stop=false
    m_seq=0;        //掷骰子次数
//    qsrand(QTime::currentTime().msec());//随机数初始化,qsrand是线程安全的,过时的函数

    while(!m_stop)  //循环主体
    {
        if (!m_Paused)
        {
//            m_diceValue=qrand();  //获取随机数,过时的函数
//            m_diceValue=(m_diceValue % 6)+1;
            m_diceValue= QRandomGenerator::global()->bounded(1,7); //随机数[1,6]

            m_seq++;
            emit newValue(m_seq,m_diceValue);  //发射信号
        }
        msleep(500); //线程休眠500ms
    }

//  在  m_stop==true时结束线程任务
    quit();//相当于  exit(0),退出线程的事件循环
}

其中 run() 时线程任务的实现部分,线程开始执行就执行 run() 函数。run 函数一般时事件循环过程,根据各种条件或者事件处理各种任务。当 run 函数退出时,线程的事件循环就结束了。
在 run 函数里,初始化变量 m_stop 和 m_seq,用 qsrand() 函数对随机数种子初始化。run 函数的主循环是个 while 循环,在主线程调用 stopThread 函数使 m_stop 为 true 才会退出 while,调用 quit 之后结束线程。
在 while 循环体内,又根据 m Paused 判断当前是否需要掷散子,如果需要掷骰子,则用随函数生成一次散子的点数 m diceValue,然后发射信号 newValueO),将 mseq 和 m diceValue 作信号参数传递出去。主线程可以设计槽函数与此信号关联,获取这两个值并进行显示。

投骰子多线程应用程序

使用 QDiceThread 类,设计一个应用程序,程序运行界面如图所示:

image.png

image.png

窗体上方的几个按钮用于控制线程的启动与停止,控制开始与暂停掷骰子。中间的文本框是示次数和点数,右边根据点数显示资源文件里面的一个图片,图片存储在项目的资源文件里。下方的一个标签根据 QDiceThread 的 staredO) 和 GnishedO) 两个信号显示线程的状态。
窗口类是从 QDialog 继承的类 Dialog,其类定义如下 (省略了按钮槽函数的定义):

class Dialog : public QDialog
{
    Q_OBJECT

private:
    QDiceThread   threadA;

protected:
    void    closeEvent(QCloseEvent *event);

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

private slots:
    void    onthreadA_started();
    void    onthreadA_finished();
    void    onthreadA_newValue(int seq, int diceValue);

private:
    Ui::Dialog *ui;
};

这里定义了一个 QDiceThread 类型的变量 threadA,重定义了 closeEvent() 事件,自定义了 3 个槽函数。
Dialog 类的构造函数代码如下:

Dialog::Dialog(QWidget *parent) : QDialog(parent),  ui(new Ui::Dialog)
{//构造函数
    ui->setupUi(this);
    connect(&threadA,SIGNAL(started()),this,SLOT(onthreadA_started()));
    connect(&threadA,SIGNAL(finished()),this,SLOT(onthreadA_finished()));

    connect(&threadA,SIGNAL(newValue(int,int)),this,SLOT(onthreadA_newValue(int,int)));
}

构造函数主要是将 threadA 的 3 个信号与 Dialog 自定义的 3 个槽函数相关联,这 3 个槽的代码如下:

void Dialog::onthreadA_started()
{//线程的started()信号的响应槽函数
    ui->LabA->setText("Thread状态:thread started");
}

void Dialog::onthreadA_finished()
{//线程的 finished()信号的响应槽函数
    ui->LabA->setText("Thread状态:thread finished");
}

void Dialog::onthreadA_newValue(int seq,int diceValue)
{//QDiceThread的newValue()信号的响应槽函数,显示骰子次数和点数
    QString  str=QString::asprintf("第 %d 次掷骰子,点数为:%d",seq,diceValue);
    ui->plainTextEdit->appendPlainText(str);

    QPixmap pic; //图片显示
    QString filename=QString::asprintf(":/dice/images/d%d.jpg",diceValue);
    pic.load(filename);
    ui->LabPic->setPixmap(pic);
}
  • started() 信号发射时,表示线程开始执行,在标签里显示状态文字。
  • finished() 信号发射时,表示线程结束执行,在标签里显示状态文字。
  • newValue() 是 QDiceThread 定义的信号, 在掷一次骰子获得新的点数后发射,将掷骰子的次数和点数传递过来。槽函数 onthreadA_newValue() 获取这两个值并显示在文本框里,再根据点数从资源文件里获取相应的图片并显示。

窗口上五个按钮的代码如下:

void Dialog::on_btnClear_clicked()
{ //清空文本 按钮
    ui->plainTextEdit->clear();
}

void Dialog::on_btnDiceEnd_clicked()
{//暂停 掷骰子按钮
    threadA.dicePause();
    ui->btnDiceBegin->setEnabled(true);
    ui->btnDiceEnd->setEnabled(false);
}

void Dialog::on_btnDiceBegin_clicked()
{//开始 掷骰子按钮
    threadA.diceBegin();
    ui->btnDiceBegin->setEnabled(false);
    ui->btnDiceEnd->setEnabled(true);
}

void Dialog::on_btnStopThread_clicked()
{//结束线程 按钮
    threadA.stopThread();//结束线程的run()函数执行
    threadA.wait();//

    ui->btnStartThread->setEnabled(true);
    ui->btnStopThread->setEnabled(false);

    ui->btnDiceBegin->setEnabled(false);
    ui->btnDiceEnd->setEnabled(false);
}

void Dialog::on_btnStartThread_clicked()
{//启动线程 按钮
    threadA.start();

    ui->btnStartThread->setEnabled(false);
    ui->btnStopThread->setEnabled(true);

    ui->btnDiceBegin->setEnabled(true);
    ui->btnDiceEnd->setEnabled(false);
}
  • “启动线程”按钮调用线程的 start () 函数,star 0 的数会内部调用 un 0 函数开始线程任务的执行。runO 函数将内部变量 m_Paused 初始化为 tue,所以,启动线程后并不会立即开始掷骰子。“开始”按钮调用 diceBegin () 函数,使 threadA 线程内部变量 mPaused 变为 false,那么 runO 函数里就开始每隔 500 毫秒产生一次骰子点数,并发射信号 newValueO。
  • “暂停”按钮调用 dicePause () 函数,使 threadA 线程内部变量 mPaused 变为 true,runO) 函数里不再掷骰子,但是 runO 函数并没有结束,也就是线程并没有结束。
  • “结束线程”按钮调用 stopThread () 函数,使 threadA 线程内部的 mstop 变为 true,runO) 函数体的 while 循环结束,执行 quit 0 后线程结束。所以,线程结束就是 runO) 函数执行退出。

重载 closeEvent () 事件,在窗口关闭时确保线程被停止,代码如下:

void Dialog::closeEvent(QCloseEvent *event)
{ //窗口关闭事件,必须结束线程
    if (threadA.isRunning())
    {
        threadA.stopThread();
        threadA.wait();
    }
    event->accept();
}

资料参考:https://github.com/0voice

标签:run,Qt,void,线程,Dialog,ui,多线程,QThread,函数
From: https://blog.csdn.net/H520xcodenodev/article/details/143528520

相关文章

  • Qt Event事件系统小探1
    目录QtEventSystemFromqt.doc如何传递事件事件类型事件处理程序事件过滤器发送事件事件的产生和派发处理我们的事件来一段好玩的代码扩展:QWidget如何处理我们的事件?扩展2:实现一个变色的LabelQtEventSystemFromqt.doc在Qt中,事件是从抽象QEvent类派......
  • windows安装cmake、opencv、qt
    配置工具1、准备好我们的安装包:2、创建一个不含中文路径文件夹:3、双击cmake安装包:(安装过程略过)勾选选择的时候注意可以选择自动添加到环境变量。安装完成后可以通过win+R键输入cmake-gui.exe去检验环境变量是否配置成功,如果可以打开则配置成功。4、双击opencv-3.4......
  • 详解 QTcpServer
    QTcpServer是Qt网络模块中用于创建TCP服务器的类。它负责接受客户端的连接并为每个连接创建相应的QTcpSocket对象。以下是对QTcpServer的详细说明,包括其功能、用法以及常用的信号和槽。主要功能监听连接:QTcpServer可以在指定的地址和端口上监听传入的TCP连接......
  • [QT QCustomPlot]实时折线图(坐标轴可缩放)
    [QTQCustomPlot]实时折线图(坐标轴可缩放)1.QCustomPlot介绍QCustomPlot是一个用于Qt框架的高性能、可扩展的图表库,专门设计用于显示和交互复杂的绘图。它提供了一个非常灵活的接口,允许开发者在Qt应用程序中轻松地实现各种图表和图形。以下是QCustomPlot的一些关键......
  • Java多线程编程(三)一>详解synchronized, 死锁,wait和notify
    目录: 一.synchronized的使用:   二. 常见死锁情况: 三.如何避免死锁:  四.wait和notify一.synchronized的使用: 我们知道synchronized锁具有互斥的特点:synchronized会起到互斥效果,某个线程执行到某个对象的synchronized中时,其他线程如果也执......
  • 桌面软件界面能给用户带来完美体验的,还得是QT的设计
    QT的界面设计具有高度的灵活性和可定制性。开发者可以利用QT的丰富工具和库,轻松创建出符合不同用户需求和审美标准的界面。无论是简洁现代的风格,还是复杂华丽的布局,QT都能胜任。其跨平台特性也是一大亮点。无论用户使用的是Windows、Mac还是Linux系统,QT设计的软件界......
  • Python中的生产者-消费者模型:多进程与多线程的实践
    Python中的生产者-消费者模型:多进程与多线程的实践在现代编程中,生产者-消费者模型是一种常见的设计模式,用于处理任务队列和并发执行。Python提供了多种工具来实现这一模型,包括threading模块和multiprocessing模块。本文将通过一个实际的案例——从网页上批量下载图片——来......
  • 【QT】Qt事件
    个人主页~Qt系统相关一、Qt事件1、事件介绍2、事件的处理label.hlabel.cpp3、QKeyEvent按键事件(1)按下单个按键(2)组合键4、QMouseEvent鼠标事件(1)鼠标单击事件(2)鼠标移动事件(3)鼠标滚轮操作5、QTimeEvent定时器事件(1)QTimerEvent(2)QTimer6、事件分发器7、事件过滤器mylab......
  • activemq - mqttv3
    相比于mqtt-client,mqttv3使用的人相对多些,如果出现问题,好排查一些。activemq部署MQTT服务查看文件:conf\activemq.xml,如果包含下面内容,activemq本身已经包含MQTT服务,不需要任何其它配置。activemq不局限于下面这些,还可以继续扩展,比如:NIO、SSL。前往官网查看:https://a......
  • Qt基础学习(三)------第一个程序
    前言    开始进入第一个程序,编写helloword来了解一下程序结构。软件    安装完成后,在开始界面会有一个如下图标的软件。,双击打开,进入到Qt软件界面。进projects,点击NEW新建项目新建窗口项目语言使用默认使用msvc2015的64版本,或者自己有的版本......