QThread Class


QThread类

标准头文件:#include <QThread>
qmake:	QT += core
继承():	QObject

枚举类型

线程的优先级

enum Priority {
    
     IdlePriority, LowestPriority, LowPriority, NormalPriority, HighPriority,, InheritPriority }

{ 空闲优先级,最低优先级,低优先级,正常优先级,高优先级,…,继承优先级 }

此枚举类型指示操作系统应该如何调度新创建的线程。

常数 价值 描述
QThread::IdlePriority 0 仅在没有其他线程运行时调度。
QThread::LowestPriority 1 调度频率低于低优先级。
QThread::LowPriority 2 计划频率低于正常优先级。
QThread::NormalPriority 3 操作系统的默认优先级。
QThread::HighPriority 4 比正常优先级计划得更频繁。
QThread::HighestPriority 5 比高优先级计划得更频繁。
QThread::TimeCriticalPriority 6 尽可能经常安排。
QThread::InheritPriority 7 使用与创建线程相同的优先级。这是默认值。

成员函数

类型 方法 说明
构造函数 QThread(QObject *parent = nullptr) 参数父类QObject指针
virtual ~QThread() 虚析构函数,当基类指针指向子类时,使用delete时,会先调用子类析构函数,在调用父类构造函数,释放资源。
QAbstractEventDispatcher * eventDispatcher() const
void exit(int returnCode = 0)
bool isFinished() const
bool isInterruptionRequested() const
bool isRunning() const
int loopLevel() const
QThread::Priority priority() const
void requestInterruption()
void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)
void setPriority(QThread::Priority priority)
void setStackSize(uint stackSize)
uint stackSize() const
bool wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever)) 阻塞线程,直到满足以下任一条件,这提供了与POSIX pthread_join()函数相似的功能。
bool wait(unsigned long time)

可重写函数

virtual bool	event(QEvent *event) override

公共槽

何为公共槽函数,就是可以被子类直接调用

void	quit()
void	start(QThread::Priority priority = InheritPriority)
void	terminate()

信号

void	finished()
void	started()

静态成员函数

QThread *	create(Function &&f, Args &&... args)
QThread *	create(Function &&f)
QThread *	currentThread()
Qt::HANDLE	currentThreadId()
int		idealThreadCount()
void	msleep(unsigned long msecs)
void	sleep(unsigned long secs)
void	usleep(unsigned long usecs) //强制当前线程休眠微秒。
//[将当前线程的执行让给另一个可运行线程(如果有)。请注意,操作系统决定切换到哪个线程。]
void	yieldCurrentThread()

保护函数

int	exec()
virtual void	run()

静态保护函数

基于enabled参数启用或禁用当前线程的终止。线程必须是由QThread启动的。

void	setTerminationEnabled(bool enabled = true)

QThread简单案例1

官方的例子,值得信赖
例如:Worker 是我们创建的一个子线程。
继承QObject的优点:内存回收安全,支持信号与槽。

例如:Controller 是主线程。

共同点:他们都继承自QObject

代码里面的connect的这种写法我比较推荐,参数怎么变都不影响,减少修改次数

这种线程的特点:任务线程里面的每个槽函数都是一个事件循环,即你可以处理耗时操作,读写文件,数据计算,大量循环等等(目前我我是使用这种方法,还不错)。

class Worker : public QObject
{
    
    
    Q_OBJECT

public slots:
    void doWork(const QString &parameter) {
    
    
        QString result;
        /* ... 处理大数据 ... */
        emit resultReady(result); //处理完数据,发到主线程显示
    }

signals:
    void resultReady(const QString &result);
};

class Controller : public QObject
{
    
    
    Q_OBJECT
    QThread workerThread;//线程栈 自动销毁,推荐使用
public:
    Controller() {
    
    
        Worker *worker = new Worker; //创建任务子线程
        worker->moveToThread(&workerThread);	//添加到线程,实际应该可以添加多个任务子线程。
        
        connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);//线程完成这个任务,就将这个任务线程对象删除
        
        connect(this, &Controller::operate, worker, &Worker::doWork);
        //发射信号,通知任务线程做事。
        
        connect(worker, &Worker::resultReady, this, &Controller::handleResults);//接收任务子线程处理好的数据
        
        workerThread.start(); //正式开启线程,
    }
    ~Controller() {
    
    
        workerThread.quit();	//先退出没处理的任务
        workerThread.wait();	//已经在处理的任务,等待处理完,在退出
    }
public slots:
    void handleResults(const QString &);
signals:
    void operate(const QString &);
};

任务插槽中的代码将在一个单独的线程中执行。但是,您可以自由地将任务线程的插槽连接到来自任何对象、任何线程的任何信号。由于一种称为排队连接的机制跨不同线程连接信号和插槽是安全的

QThread简单案例2

让代码在单独的线程中运行的另一种方法是子类化QThread并重新实现run()。这种使用的场景一般是不需要和主线程交互,比如只完成文件写操作等等。
例如:

//任务线程
class WorkerThread : public QThread
{
    
    
    Q_OBJECT
    void run() override {
    
    
        QString result;
        /* ... here is the expensive or blocking operation ... */
        emit resultReady(result);
    }
signals:
    void resultReady(const QString &s);
};
//主线程 分配任务
void MyObject::startWorkInAThread()
{
    
    
    WorkerThread *workerThread = new WorkerThread(this);//传入this,就是QObject的指针,资源的释放,即是线程的构造函数传参。
    
    connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
    
    connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
    
    workerThread->start();//开启run()方法
}

在该示例中,线程将在run函数返回后退出。除非调用exec(),否则线程中不会运行任何事件循环(即做完这件事,就不再执行事件循环了)。


重要的是要记住,QThread实例存在于实例化它的旧线程中,而不是存在于调用run()的新线程中。这意味着所有QThread的队列槽和调用的方法都将在旧线程中执行。因此,希望在新线程中调用槽的开发人员必须使用工作对象方法;新插槽不应该直接在子类化的QThread中实现。


与排队槽或调用的方法不同,直接在QThread对象上调用的方法将在调用该方法的线程中执行。当子类化QThread时,请记住构造函数在旧线程中执行(主线程id一致),而run()在新线程中执行(线程id新的)。如果一个成员变量是从两个函数中访问的,那么这个变量是从两个不同的线程中访问的。检查这样做是否安全。


注意:在跨不同线程与对象交互时必须小心。一般来说,函数只能从创建QThread对象本身的线程中调用(例如setPriority()),除非文档中另有说明。

猜你喜欢

转载自blog.csdn.net/m0_45463480/article/details/130905992