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

示例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

posted @ 2024-11-20 15:09  [BORUTO]  阅读(208)  评论(0编辑  收藏  举报