首页 > 其他分享 >Qt - 多线程之线程的开始、暂停、恢复、停止

Qt - 多线程之线程的开始、暂停、恢复、停止

时间:2024-11-20 14:56:07浏览次数:1  
标签:Widget 多线程 Qt thread void 线程 include QThread

示例1

在Qt中,可以使用QThread的线程控制功能来暂停和恢复一个线程。这里是一个简单的例子:

 
#include <QThread>
#include <QDebug>
 
class WorkerThread : public QThread {
    void run() override {
        qDebug() << "Thread is running";
        // 执行一些任务
        for (int i = 0; i < 5; ++i) {
            msleep(1000); // 模拟工作
            if (isInterruptionRequested()) {
                qDebug() << "Thread is interrupted";
                return;
            }
        }
        qDebug() << "Thread is finished";
    }
};
 
void pauseThread(QThread* thread) {
    thread->requestInterruption(); // 请求暂停
    while (thread->isRunning()) {
        // 等待线程暂停
    }
}
 
void resumeThread(QThread* thread) {
    thread->start(); // 重新开始线程
}
 
int main() {
    WorkerThread thread;
    thread.start();
 
    // 假设需要暂停线程
    pauseThread(&thread);
 
    // 假设在这里做一些其他的事情
 
    // 现在我们要恢复线程
    resumeThread(&thread);
 
    // 等待线程结束
    thread.wait();
 
    return 0;
}

在这个例子中,我们定义了一个WorkerThread类,它是QThread的子类,并且在run函数中执行了一些模拟任务。我们使用requestInterruption()来请求暂停线程,并且在run函数中检查isInterruptionRequested()来决定是否退出。

pauseThread函数请求暂停并且循环等待线程真正暂停。resumeThread函数则简单地重新开始线程。在main函数中,我们创建了一个WorkerThread对象,启动了线程,然后调用pauseThread来暂停它,接着我们可以恢复线程。

请注意,这个例子是为了演示如何暂停和恢复线程。在实际应用中,请确保你不会因为暂停一个线程而导致数据不一致或者其他的线程安全问题。此外,这种方法不适用于那些已经在等待事件发生的线程,因为在等待期间线程不会检查中断请求。

 

 

示例2

示例2是根据示例1优化之后的代码

项目目录结构:

mythread.h

 
#ifndef MYTHREAD_H
#define MYTHREAD_H


#include <QThread>

class Widget;

class MyThread : public QThread
{
    Q_OBJECT
public:
    explicit MyThread(Widget* wid,QObject *parent = nullptr);
    ~MyThread();

protected:
    void run() override;

private:
    Widget* m_wid;
    int m_pRecordingFlag;

signals:
};


#endif // MYTHREAD_H

mythread.cpp

 
#include "mythread.h"
#include <QDebug>
#include "widget.h"

MyThread::MyThread(Widget* wid, QObject *parent): QThread(parent)
{
    m_wid = wid;
    m_pRecordingFlag = 1;
}

MyThread::~MyThread()
{
    qDebug()<<   "MyThread::~MyThread()";
}

void MyThread::run()
{
    qDebug() << "当前线程对象的地址: " << QThread::currentThread();
    while (1)
    {
        if (28 < m_pRecordingFlag)
        {
            m_pRecordingFlag = 1;
        }
        qDebug() << "m_pRecordingFlag = "<<m_pRecordingFlag;
        m_wid->loadPixmap(m_pRecordingFlag);
        m_wid->setPixmap();
        QThread::msleep(100);
        m_pRecordingFlag++;

        if (isInterruptionRequested())
        {
            qDebug() << "Thread is interrupted";
            return;
        }
    }
}

widget.h

 
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "mythread.h"

#include <QLabel>
#include <QPixmap>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void pauseThread(QThread* thread);
    void resumeThread(QThread* thread);

    void loadPixmap(int flag);
    void setPixmap();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

private:
    Ui::Widget *ui;

    MyThread* mythread;

    QPixmap m_Pixmap;
    QLabel* m_Label;
};
#endif // WIDGET_H

widget.cpp

 
#include "widget.h"
#include "ui_widget.h"

#include<QDebug>
#include<QThread>



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

    m_Label = new QLabel(this);
    m_Label->setFixedSize(760,140);
    //m_Label->setText("fdsf9999999999999");
    m_Label->setScaledContents(true);//设置内容缩放

    mythread = new MyThread(this,this);//创建线程
    connect(mythread,&QThread::started,this,[](){qDebug()<<"start";});
    connect(mythread,&QThread::finished,this,[](){qDebug()<<"finished";});
    qDebug() << "主线程对象的地址: " << QThread::currentThread();

}

Widget::~Widget()
{
    mythread->quit();//退出线程
    delete mythread;
    delete ui;
}


void Widget::pauseThread(QThread* thread)
{
    thread->requestInterruption(); // 请求暂停
    while (thread->isRunning())
    {
        // 等待线程暂停
    }
}

void Widget::resumeThread(QThread* thread)
{
    thread->start(); // 重新开始线程
}


void Widget::on_pushButton_clicked()
{
    resumeThread(mythread);
}

void Widget::on_pushButton_2_clicked()
{
    pauseThread(mythread);
}

void Widget::loadPixmap(int flag)
{
    m_Pixmap.load(QString(":/recording/recording_%1.png").arg(flag));
}

void Widget::setPixmap()
{
    m_Label->setPixmap(m_Pixmap);
}

运行效果:

 

 

示例3

一.前言

软件开发中,使用到线程就不可避免的要实现线程的暂停恢复停止等操作,总不可能说线程一旦启动就直接运行到结束了,中途不能停止啥的。线程的开始以及结束都比较简单,都有对应的接口可以调用,线程的暂停以及恢复就需要自己手动写个接口,关键在于使用线程锁来实现这个过程。

二.实现过程

1.1先继承QThread实现自己的线程类,声明线程锁变量,以及暂停恢复停止的接口

1.2核心代码(thread3.h)

 
/*
 * 线程开始 暂停 恢复 停止 例程
 * V1.0 2021-12-27
*/

#ifndef THREAD3_H
#define THREAD3_H

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

class Thread3 : public QThread
{
public:
    Thread3();
    ~Thread3()
    {}

public:
    void close();
    void pauseThread();
    void resumeThread();

protected:
    void run();

private:
    volatile bool stop;
    bool pause;//作为线程状态的一个记录
    QMutex pauseLock;
    int i;
};

#endif // THREAD3_H

 

1.3其他说明

增加关键字volatile是为了:提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,就会出现不一致的现象

2.核心代码(thread3.cpp)

 
#include "Thread3.h"

Thread3::Thread3()
{
    stop=false;
    pause=false;
    i=0;
}

void Thread3::close()
{
    stop=true;
    quit();
    wait();
}

void Thread3::pauseThread()
{
    qDebug()<<"pauseThread";
    this->pauseLock.lock();
    pause=true;
}

void Thread3::resumeThread()
{
    qDebug()<<"resumeThread";
    this->pauseLock.unlock();
    pause=false;
}

void Thread3::run()
{
    while(i<10)
    {
        if(!stop)
        {
            // 线程锁在业务开始和和结束的地方
            pauseLock.lock();

            // 具体的业务逻辑
            i++;
            qDebug()<<i<<"-"<<QTime::currentTime()<<"-"<<"CurrnetThreadID:"<<QThread::currentThreadId();
            msleep(1000);

            //
            pauseLock.unlock();
        }
        else
        {
            break;
        }
    }
}

3.1核心代码 (widget.h)

 
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "thread3.h"

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

    void on_pushButton_3_clicked();

    void on_pushButton_4_clicked();

private:
    Ui::Widget *ui;

    Thread3* thread;
};
#endif // WIDGET_H

3.2核心代码 (widget.cpp)

 
#include "widget.h"
#include "ui_widget.h"

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

    qDebug()<<"主线程ID:"<<QThread::currentThreadId();

    thread = new Thread3();//创建线程

}

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

void Widget::on_pushButton_1_clicked()
{
    qDebug()<<"线程开始";
    thread->start();
}

void Widget::on_pushButton_2_clicked()
{
    qDebug()<<"线程暂停";
    thread->pauseThread();
}

void Widget::on_pushButton_3_clicked()
{
    qDebug()<<"线程恢复";
    thread->resumeThread();
}

void Widget::on_pushButton_4_clicked()
{
    qDebug()<<"线程停止";
    thread->close();
}

 

3.3效果预览

 

三.其他

1.本文只是简单实现线程的开始暂停恢复以及停止功能,但是实际运用过程中,还需要增加诸多的逻辑处理,比如暂停之前判断线程的状态再执行,恢复之前判断线程的状态再执行恢复等

 

 

——————————————

原文链接:https://blog.csdn.net/Joker__123/article/details/122165065

标签:Widget,多线程,Qt,thread,void,线程,include,QThread
From: https://www.cnblogs.com/zhuchunlin/p/18558406

相关文章

  • QT5.15.2 连接MySQL 驱动问题解决方案,无论菜鸟️还是老鸟,解决了就是好鸟
    最近在学QT,现在QT只能在线安装了,用了几天,看到数据库时,需要用MySQL,结果出现了问题。QSqlDatabase:QMYSQLdrivernotloaded、QSqlDatabase:availabledrivers:QSQLITEQODBCQODBC3QPSQLQPSQL7、Sqlconnectfailed、"DrivernotloadedDrivernotloaded"网上找到很多......
  • Qt 重写paintEvent事件划线
    可以自定义一个类QtImageLabel继承于QLabel,重写paintEvent事件划线,写文字等。如果用ui设计,将QLabel控件提升为QtImageLabel类型即可。QtImageLabel.hprotected:voidpaintEvent(QPaintEvent*)override;QtImageLabel.cpp#pragmaexecution_character_set("utf-8......
  • 模拟线程池与异步方法调用查询接口优化
    问题:批量查询如何优化?entity实体类packagecom.itheima.alipay.prop;importlombok.Data;@DatapublicclassUserInfo{privateLonguserId;privateStringusername;privateintage;publicUserInfo(LonguserId,Stringusername,intage){......
  • QT 实现表格展示第一列为CheckBox(复选框)
    1.界面实现效果在Qt中,如果你想要在QTableView中实现复选框展示数据,示例:实现第一列为复选框(checkBox),需要自定义的QAbstractTableModel,重写data和setData方法来返回和设置复选框的状态,并且还需要重写flags方法来允许复选框被点击。2.自定义CustomModel需要实现以下几个方......
  • Java面试之多线程&并发篇(6)
    前言本来想着给自己放松一下,刷刷博客,突然被几道面试题难倒!产生死锁的四个必要条件?如何避免死锁?线程池核心线程数怎么设置呢?Java线程池中队列常用类型有哪些?似乎有点模糊了,那就大概看一下面试题吧。好记性不如烂键盘***12万字的java面试题整理******java核心面试知识整理***......
  • C#单线程环境下实现每秒百万级调度
    C#并发控制框架:单线程环境下实现每秒百万级调度 阅读目录前言并发流程控制框架框架优势框架示例框架地址总结最后前言在工业自动化和机器视觉领域,对实时性、可靠性和效率的要求越来越高。为了满足这些需求,我们开发了一款专为工业自动化运动控制和机器视觉流程开发......
  • Qt Label 显示图片
    一般这样子://跟随比例变化ui->label->setScaledContents(true);QPixmappixmap("./01.jpg");//pixmap.load("./01.jpg");//让图片大小适应控件大小,如果不需要,可以直接显示原图QPixmaps_img=pixmap.scaled(ui->label->size(),Qt::KeepAspectRatio,Qt::SmoothTran......
  • Linux线程退出、资源回收、资源清理的方法
    参考 Linux线程退出、资源回收、资源清理的方法_linux线程退出会释放哪些资源-CSDN博客 首先说明线程中要回收哪些资源,理解清楚了这点之后在思考资源回收的问题。1、子线程创建时从父线程copy出来的栈内存;线程退出有多种方式,如return,pthread_exit,pthread_cancel等;线......
  • 第 1 章 并发编程线程基础
    目录1.1什么是线程 1.2线程创建与运行 1、继承Thread类方式的实现。2、实现Runnable接口的run方法3、使用FutureTask方式1.3线程通知与等待1.wait()函数2.wait(longtimeout)函数3.wait(longtimeout,intnanos)函数4.notify()函数5.notifyAll()......
  • Qt 16进制颜色 QColor
    一、16进制转rgb(a)1、QColor类可以通过字符串作为参数来创建表示RGBA值的颜色对象。字符串必须满足以下格式,RGB(红、绿、蓝):#RRGGBB或者#RGB,其中RR、GG、BB表示16进制的红、绿、蓝分量的值。RGBA(红、绿、蓝、透明度):#RRGGBBAA或者#RGBA,其中RR、GG、BB表示16......