一个应用程序一般只有一个线程,一个线程内的操作是顺序执行的,如果有某个比较消耗时间的计算或操作,比如网络通信中的文件传输,在一个线程内操作时,用户界面就可能会冻结而不能及时响应,在这种情况下,可以创建一个单独的线程来执行比较消耗时间的操作,并与主线程之间处理好同步与数据交互,这就是多线程应用程序。
在qt中使用了多线程,有些事项是需要额外注意的:
默认的线程在Qt中称之为窗口线程,也叫主线程(UI线程),负责窗口事件处理或者窗口控件数据的更新。
子线程负责后台的业务逻辑处理,子线程中不能对窗口对象做任何操作,这些事情需要交给窗口线程处理。
主线程和子线程之间如果要进行数据的传递,需要使用Qt中的信号槽机制。
QThread类提供不依赖于平台的管理线程的方法。
Header: #include
qmake: QT += core
inherits: QObject
// 构造函数
QThread(QObject* parent = Q_NULLPTR);
// 判断线程中的任务是否处理完成
bool isFinished() const;
// 判断线程是否正在运行
bool isRunning() const;
// 返回线程的优先级
Priority priority() const;
// 设置线程的优先级
void setPriority(Priority priority);
// 退出线程的事件循环,退出码为returnCode,0表示退出成功;否则表示错误
void exit(int returnCode = 0);
// 阻止线程执行,直到线程结束(从run()函数返回),或等待时间超过time毫秒
bool wait(unsigned long time = ULONG_MAX);
// 退出线程的事件循环,并返回代码0,等效于exit(0)
void quit();
// 内部调用run()开始执行线程,操作系统根据priority参数进行调度
void start(Priority priority = inheritPriority);
// 终止线程的执行,但不是立即结束线程,而是等待操作系统结束线程。使用terminate()之后应使用wait()
void terminate();
// 在线程就要结束时,发射此信号
void finished();
// 在线程开始执行、run()函数被调用之前发射此信号
void started();
// 返回一个指向管理当前执行线程的QThread的指针
QThread* currentThread();
// 返回系统上能运行的线程的理想个数
int idealThreadCount();
// 强制当前线程休眠msecs毫秒
void msleep(unsigned long msecs);
// 强制当前线程休眠secs秒
void sleep(unsigned long secs);
// 强制当前线程休眠usecs微秒
void usleep(unsigned long usecs);
// 由run()函数调用,进入线程的事件循环,等待exit()退出
int exec();
// start()调用run()函数开始执行线程任务的执行,所以在run()函数里实现线程的任务功能
virtual void run();
一个QThread类的对象管理一个线程,一般从QThread继承一个自定义类,并重定义run()函数,在run()函数里实现线程需要完成的任务。一般在主线程里创建工作线程,并调用start()开始执行工作线程的任务。start()函数会在内部调用run()函数,进入工作线程的事件循环,在run()函数里调用exit()或quit()可以结束线程的事件循环,或在主线程里调用terminate()强制结束线程。
1.创建一个线程类的子类,让其继承QT中的线程类QThread
class MyThread:public QThread
{
......
}
2.重写QThread类的run()方法,在该函数内部编写子线程要处理的具体的业务流程
class MyThread:public QThread
{
......
protected:
void run()
{
......
}
}
3.在主线程中创建子线程对象
4.启动子线程,调用start()方法
3.1操作步骤
1.创建一个工作类,让这个类从QObject派生
class MyWork : public QObject
{
......
}
2.在这个类中添加一个公共的成员函数,函数体就是我们要子线程中执行的业务逻辑
class MyWokr : public QObject
{
public:
......
// 工作函数
void working();
}
3.在主线程中创建一个QThread对象,这个就是子线程的对象
QThread* sub = new QThread;
4.在主线程中创建工作的类对象(不能指定给创建的对象指定父对象)
MyWork* work = new MyWork;
5.将MyWork对象移动到创建的子线程中,需要调用QObject类提供的moveToThread()方法
work->moveToThread(sub);
6.启动子线程,调用start(),这个时候线程启动了,但是移动到线程中的对象并没有工作
7.调用MyWork类对象的工作函数,让这个函数开始执行,这个时候是在移动到的内个子线程中运行的
给创建的线程类QThread指定父对象。由Qt的对象树机制,自动回收资源。
通过信号槽来回收资源。当当前窗口析构时会发出信号:destroyed()。
connect(this, &MainWindow::destroyed, this, [=]()
{
thread->quit();
thread->wait();
thread->deleteLater();
});