Qt多线程(继承QThread、QObject简单实例代码对比)

2 篇文章 0 订阅

一.代码

1.1 继承QThread

#ifndef Thread_CopyFile_H
#define Thread_CopyFile_H

#include <QThread>

class Thread_CopyFile : public QThread
{
    Q_OBJECT
public:
    Thread_CopyFile(QObject * parent = 0);

protected:
    void run(); // 新线程入口

signals:
    void percentCopied(double percent);
    void finished();
    void errorOccurred();

public slots:
    void cancelCopy();

private:
    bool m_canceled;
};

#endif // Thread_CopyFile_H
#include "Thread_CopyFile.h"
#include <QFile>
#include <QFileInfo>
#include "common.h"
#include <QDebug>

Thread_CopyFile::Thread_CopyFile(QObject *parent)
    : QThread(parent)
{
    // 新线程的初始化不要放在这里
}

void Thread_CopyFile::run()
{
    // 新线程入口
    // 初始化和操作放在这里
    m_canceled = false;
    QFile src(SrcFile);
    QFile cpy(CpyFile);
    qint64 srcSize = QFileInfo(src).size();//9000
    int bytesWritten = 0;
    if (srcSize==0 || !src.open(QFile::ReadOnly))
    {
        emit errorOccurred();
        return;
    }
    if (cpy.exists())
    {
        cpy.resize(0);//清空目标txt内容
    }
    if (!cpy.open(QFile::WriteOnly))
    {
        src.close();
        emit errorOccurred();
        return;
    }
    qDebug()<<"curThreadId()=="<<QThread::currentThreadId();
    while (!src.atEnd())
    {
        if (m_canceled)
        {
            src.close();
            cpy.close();
            cpy.remove();
            return;
        }
        msleep(8);
        qint64 wrt = cpy.write(src.readLine());//9
        if (wrt < 0)
        {
            emit errorOccurred();
            src.close();
            cpy.close();
            cpy.remove();
            return;
        }
        bytesWritten += wrt;
        emit percentCopied(bytesWritten*1.0/srcSize);//返回百分比
    }
    src.close();
    cpy.close();
    emit finished();
}

void Thread_CopyFile::cancelCopy()
{
    m_canceled = true;
}

1.2 继承QObject

#ifndef OBJECT_COPYFILE_H
#define OBJECT_COPYFILE_H

#include <QObject>

class Object_CopyFile : public QObject
{
    Q_OBJECT
public:
    explicit Object_CopyFile(QObject *parent = 0);

signals:
    void percentCopied(double percent);
    void finished();
    void errorOccurred();

public slots:
    void startCopying();
    void cancelCopying();

private:
    bool m_canceled;
};

#endif // FILECOPIER_H
#include "Object_CopyFile.h"
#include "common.h"
#include <QFile>
#include <QFileInfo>
#include <QThread>
#include <QDebug>

Object_CopyFile::Object_CopyFile(QObject *parent) : QObject(parent)
{
    // 这个类与多线程的实现没有直接的关系,它就老老实实地做好自己的事情
    m_canceled = false;
}

void Object_CopyFile::startCopying()
{
    qDebug()<<"curThreadId()=="<<QThread::currentThreadId();
    m_canceled = false;
    QFile src(SrcFile);
    QFile cpy(CpyFile);
    qint64 srcSize = QFileInfo(src).size();
    int bytesWritten = 0;
    if (srcSize==0 || !src.open(QFile::ReadOnly))
    {
        emit errorOccurred();
        return;
    }
    if (cpy.exists())
    {
        cpy.resize(0);
    }
    if (!cpy.open(QFile::WriteOnly))
    {
        src.close();
        emit errorOccurred();
        return;
    }

    while (!src.atEnd())
    {
        if (m_canceled)
        {
            src.close();
            cpy.close();
            cpy.remove();
            return;
        }
        QThread::msleep(8);
        qint64 wrt = cpy.write(src.readLine());
        if (wrt < 0)
        {
            emit errorOccurred();
            src.close();
            cpy.close();
            cpy.remove();
            return;
        }
        bytesWritten += wrt;
        emit percentCopied(bytesWritten*1.0/srcSize);
    }
    src.close();
    cpy.close();
    emit finished();
}

void Object_CopyFile::cancelCopying()
{
    m_canceled = true;
}

1.3 调用

private:
    Ui::MainWindow *ui;
    Thread_CopyFile *m_Thr; // 用于复制文件的子线程

    Object_CopyFile *m_Obj; // 用户复制文件的类
    QThread *m_Thread;      // m_Obj将被移动到此线程执行

    Object_CopyFile *m_Obj2;// 用户复制文件的类
//方式一 自定义线程,继承QThread重写run()函数,复制任务在run中完成
    m_Thr = new Thread_CopyFile(this);
    connect(m_Thr, SIGNAL(errorOccurred()),this, SLOT(errorHandleSlot()));
    connect(m_Thr, SIGNAL(percentCopied(double)),this, SLOT(updateCopyProgress(double)));
    connect(m_Thr, SIGNAL(finished()),this, SLOT(copyFinishSlot()));

    //方式二 继承QObject,使用MoveToThread
    m_Obj = new Object_CopyFile; // 这个实例要负责复制任务,不要设置parent
    m_Thread = new QThread; // 子线程,本身不负责复制
    // 将实例移动到新的线程,实现多线程运行

    connect(this, SIGNAL(startCopyRsquested()), m_Obj, SLOT(startCopying()));
    connect(this, SIGNAL(cancelCopuRequested()), m_Obj, SLOT(cancelCopying()));
    connect(m_Obj, SIGNAL(errorOccurred()),this, SLOT(errorHandleSlot()));
    connect(m_Obj, SIGNAL(percentCopied(double)),this, SLOT(updateCopyProgress(double)));
    connect(m_Obj, SIGNAL(finished()),this, SLOT(copyFinishSlot()));
    m_Obj->moveToThread(m_Thread);
    //connect(m_childThread,SIGNAL(started()),m_copier,SLOT(startCopying()));  //开启线程槽函数
    //m_Thread->start(); //启动子线程

    //单线程(继承QObject,不使用MoveToThread)
    m_Obj2 = new Object_CopyFile;
    connect(this, SIGNAL(startCopyRsquested2()), m_Obj2, SLOT(startCopying()));
    connect(this, SIGNAL(cancelCopuRequested2()), m_Obj2, SLOT(cancelCopying()));
    connect(m_Obj2, SIGNAL(errorOccurred()),this, SLOT(errorHandleSlot()));
    connect(m_Obj2, SIGNAL(percentCopied(double)),this, SLOT(updateCopyProgress(double)));
    connect(m_Obj2, SIGNAL(finished()),this, SLOT(copyFinishSlot()));
...
void MainWindow::on_btnCopy1_clicked()
{
    m_Thr->start(); // 复制文件的新线程开始(用start()自动调用run())
}

void MainWindow::on_btnCopy2_clicked()
{
    qDebug()<<"Main btnCopy2 threadId()=="<<QThread::currentThreadId();
    m_Thread->start();   //需start才能有效传信号槽
    emit startCopyRsquested();  //m_childThread不start时槽函数不响应
}

void MainWindow::on_btnCopy3_clicked()
{
    qDebug()<<"Main btnCopy3 threadId()=="<<QThread::currentThreadId();
    emit startCopyRsquested2();
}

以文件复制为例作简单对比
在这里插入图片描述

二.细节笔记

2.1 线程暂停

A.继承QThread
方式一 利用标志位,使其线程退出
方式二 优雅的结束线程(阻塞,子线程仍继续执行)

wait();
quit();

方式三 暴力结束(阻塞,可能会卡死致崩)

terminate();

QThread如何优雅实现暂停(挂起)功能
QThread之terminate()
B.继承QThread,MoveToThread

三.参考链接

以文件复制为例将继承QThread、QObject,两种Qt多线程方式作简单对比
Github某星夜之夏
Qt使用多线程的一些心得——2.继承QObject的多线程使用方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值