一 qt线程角色
子线程完成与UI线程无关的工作,并且能够保持与UI线程通信
二 qt中线程
在QT中,对于 线程操作也是提供类(QThread)来进行封装,然后再学习该类的API接口
参数 | 用途 |
---|---|
Header: | #include |
qmake: | QT = core |
Inherits: | QObject //继承于QObject |
从官方文档可以看出,如果一个线程类要支持信号和槽,那么,该类要直接或者间接的继承于QObject类,并且在类中要声明宏:Q_OBJECT
2.1 线程的创建
线程的创建方式:自定义一个类继承于QThread,并且 重写该类的run函数,run函数中,就是 子线程要执行任务。在创建线程后,要进行启动线程 操作
代码语言:javascript复制class WorkerThread : public QThread
{
void run() override { //该函数是一个普通成员函数,执行后就结束退出
//如果想要子线程一直执行,则要使用while
//子线程要的执行任务
}
};
代码语言:javascript复制 WorkerThread *workerThread = new WorkerThread(this);
workerThread->start();//子线程一定要调用start启动,否则,不会执行
线程的几点注意事项:
- 默认情况下,void run() 只执行一次,想要执行多次,要手动使用循环语句
- 子线程一定要调用start启动,否则,不会执行
- 对于信号和槽,在子线程中,不是必须使用,除非,要使用信号和槽来跟其他线程通信
线程实现的步骤:
第一步:创建一个子类继承于QThread,并且重写run函数
第二步:创建子线程对象
第三步:启动子线程 ---- start()
2.2 线程类的基本接口和使用
启动 和终止线程
参数 | 用途 |
---|---|
void | quit() //退出一个线程循环,可以起作 停止线程 |
void | start(QThread::Priority priority = InheritPriority)//启动线程 |
void | terminate()//终止线程 |
静态成员函数接口:
参数 | 用途 |
---|---|
void | msleep(unsigned long msecs)//毫秒级 |
void | sleep(unsigned long secs)//秒级 |
void | usleep(unsigned long usecs)//微秒 |
参数 | 用途 |
---|---|
QThread * | currentThread() //获取当前的线程 |
Qt::HANDLE | currentThreadId()//返回的ID值给是QT内部使用,应用程序不能使用 |
来自于QObject类中的成员函数:设置和获取线程的名字
参数 | 用途 |
---|---|
void | setObjectName(const QString &name) |
QString | objectName() const |
基本案例:利用子线程来实现计数,并将计数的结果更新到UI 第一步:创建子线程类
代码语言:javascript复制//发一条通知给UI线程(UI控件)
class MyThread : public QThread
{
Q_OBJECT //在该类中,可以支持信号和槽,另外,该类还要间接或者直接继承于QObject
public:
explicit MyThread(QObject *parent = nullptr){}
~MyThread(){}
void run() override
{
static int i = 0;
while (1) {
QThread::sleep(1);
emit sendMsg(QString::number(i ));
}
}
signals:
void sendMsg(const QString&msg);
};
第二步:在UI线程中,创建子线程并启动子线程
代码语言:javascript复制 thread = new MyThread(this)
//建立子线程与UI线程(MainWindow)的信号和槽连接
connect(thread,&MyThread::sendMsg,this,&MainWindow::recvMsg);
thread->start();//启动线程
第四步:在UI线程的槽函数中,更新UI控件
代码语言:javascript复制void MainWindow::recvMsg(const QString &msg)
{
ui->label->setText(msg);
}
第五步:终止子线程
代码语言:javascript复制void MainWindow::on_stopButton_clicked()
{
thread->terminate(); //终止线程
}
三 线程同步
线程同步方式:
- 互斥锁
- 读写锁
- 信号量
线程同步:多个线程之间在处理数据时,按照一 定次序来进行完成,比如:
- 数据接收 — 数据处理 — 数据发送,把这个过程称之为线程同步。
在QT线程 编程中,也提供线程同步机制:QMutex
QMutexLocker
QReadWriteLock
QSemaphore
QWaitCondition
同步机制的目的是为了保护数据或者代码段,在多线程中,每次只允许一个线程来进行访问 在线程同步中,把要保护的数据或者代码段的上下文叫作临界区 临界区中所包含的资源就是临界资源,比如:变量 寄存器
代码语言:javascript复制static int number = 0;
static QMutex mutex;
class Work1Thread:public QThread
{
public:
explicit Work1Thread(QWidget *parent = nullptr){}
~Work1Thread(){}
void run()override
{
while (1) {
mutex.lock();
QThread::sleep(2);
qDebug() << "Work1Thread"<<number ;
mutex.unlock();
}
}
};
class Work2Thread:public QThread
{
public:
explicit Work2Thread(QWidget *parent = nullptr){}
~Work2Thread(){}
void run()override
{
while (1) {
mutex.lock();
QThread::sleep(1);
qDebug() << "Work2Thread"<<number ;
mutex.unlock();
}
}
};