QThread
- QThread类
- 枚举类型
- 成员函数
- 可重写函数
- 公共槽
- 信号
- 静态成员函数
- 保护函数
- 静态保护函数
- QThread简单案例1
- QThread简单案例2
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_OBJECTpublic slots:void doWork(const QString ¶meter) {QString result;/* ... 处理大数据 ... */emit resultReady(result); //处理完数据,发到主线程显示}signals:void resultReady(const QString &result);
};class Controller : public QObject
{Q_OBJECTQThread 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_OBJECTvoid 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()),除非文档中另有说明。