QThread的使用

Qt 多线程注意事项

Qt中使用多线程的注意事项:

  • 默认的线程在Qt中称之为窗口线程,也叫主线程,负责窗口事件处理或者窗口控件数据的更新
  • 子线程负责后台的业务逻辑处理,子线程中不能对窗口对象做任何操作,这些事情需要交给窗口线程处理
  • 主线程和子线程之间如果要进行数据的传递,需要使用Qt中的信号槽机制

QThread

常用函数

// 判断线程中的任务是不是处理完成
bool QThread::isFinished() const;
// 判断子线程是否运行
bool QThread::isRunning() const;
// 当前线程的优先级
Priority QThread::priority() const;
void QThread::setPriority(Priority priority);
// 优先级:
//    QThread::IdlePriority         --> 最低的优先级
//    QThread::LowestPriority
//    QThread::LowPriority
//    QThread::NormalPriority
//    QThread::HighPriority
//    QThread::HighestPriority
//    QThread::TimeCriticalPriority --> 最高的优先级
//    QThread::InheritPriority      --> 子线程和其父线程的优先级相同, 默认是这个

// 退出线程函数
void QThread::exit(int returnCode = 0);

// 调用线程退出函数之后, 线程不会马上退出;因为当前任务有可能还没有完成, 调回用这个函数是等待任务完成, 然后退出线程, 一般情况下会在 exit() 后边调用这个函数
bool QThread::wait(unsigned long time = ULONG_MAX);

退出线程

QThread的函数在运行完run函数后就视为线程完成,会发射finish信号。

子线程指针,尽量不要去delete ,这样不安全。一般会绑定QObject::deleteLater()方法。

connect(pThread,&QThread::finished ,thread,&QObject::deleteLater);

正常的退出线程其实质是退出事件循环(实际运用中是执行完run()函数),即执行exit(int returnCode = 0)函数。返回0代表成功,其他非零值代表异常。quit() 函数等价于 exit(0)。线程退出后会发出 finished() 信号。

SIGNAL、SLOT

// 和调用 exit() 效果是一样的
// 调用这个函数之后, 再调用 wait() 函数
[slot] void QThread::quit();
// 启动子线程
[slot] void QThread::start(Priority priority = InheritPriority);

// 线程退出, 可能是会马上终止线程, 一般情况下不使用这个函数(可能会出错)
[slot] void QThread::terminate();

// 线程中执行的任务完成了, 发出该信号
// 任务函数中的处理逻辑执行完
[signal] void QThread::finished();
// 开始工作之前发出这个信号, 一般不使用
[signal] void QThread::started();

常用静态函数

// 返回当前执行线程的QThread的指针
[static] QThread *QThread::currentThread();
// 返回可以在系统上运行的理想线程数 和当前电脑的 CPU 核心数相同
[static] int QThread::idealThreadCount();
// 休眠函数
[static] void QThread::msleep(unsigned long msecs);	// 单位: 毫秒
[static] void QThread::sleep(unsigned long secs);	// 单位: 秒
[static] void QThread::usleep(unsigned long usecs);	// 单位: 微秒

使用方式一

继承QThread,实现run函数

[virtual protected] void QThread::run();
class myThread:public QThread{
   protected:
    void run(){
        //  实现
    }
    
signals:
    void SigFinished(void);// run()函数执行结束后自动触发
}
myThread * subThread = new myThread();
connect(myThread, &myThread::SigFinished, myThread, QThread::deleteLater);//自动释放
subThread->start(); // 启动线程

如果线程中有操作UI或者与其他模块交互的需求;通过信号将信息传递出去。

#include <QThread>

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

protected:
    void run(){
        qDebug() << "当前线程对象的地址: " << QThread::currentThread();

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

signals:
    // 自定义信号, 传递数据
    void curNumber(int num);

public slots:
};

使用方式二

  • 从QObject派生一个类

  • 类中添加一个公共成员函数(也可以添加多个,在不同的线程中执行),函数就是要在线程中执行的业务

class MyWork:public QObject{
public:
    // 函数名称自定义,合法名称都可以
    void myWork();
}
  • 主线程中创建一个QThread对象,和work对象
QThread * sub = new QThread();
// 如果给woker指定了父对象, 这个函数调用就失败了
MyWork * worker = new MyWork();
// 移动到子线程中工作
worker->moveToThread(sub);
// 连接QThread的started信号,在调用sub->start()开始执行myWork()
QObject::connect(sub, &QThread::started, worker, &MyWork::myWork); // 连接信号和槽函数
sub->start(); // 启动新线程

moveToThread函数的注意事项:

  • 只有QObject对象可以使用moveToThread函数,其他对象不能使用。
  • 一旦调用了moveToThread函数,这个对象的线程上下文就会改变,因此在调用该函数之后,这个对象所属的线程上下文不能再使用。
  • 如果对象正在执行某个函数,而该函数又没有使用线程锁,那么在移动对象之后,该函数仍然会在原来的线程中执行。因此,在移动对象之前,需要确保该对象不处于执行状态。
  • 如果一个QObject对象的子对象也需要移动到新线程中,那么这些子对象也必须调用moveToThread函数进行移动。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值