1.QThread 常用的函数
exec()
:进⼊事件循环并等待exit()
被调⽤,返回传递给exit()
的值- 如果通过
quit()
调⽤exit()
, 返回值为0 - 这个函数应该在
run()
中调⽤,必须调⽤此函数来启动事件处理
- 如果通过
exit()
:告诉线程的事件循环退出并返回代码currentThread()
:返回⼀个指向管理当前执⾏线程的QThread
的指针idealThreadCount()
:返回可在系统上运⾏的理想线程数- 这是通过查询系统中实际的和逻辑的处理器内核的数量来完成的
- 如果⽆法检测到处理器核数,则此函数返回1
isRunning()
:如果线程正在运⾏则返回true
,否则返回false
msleep()
:强制当前线程休眠,单位为毫秒sleep()
:强制当前线程休眠数秒- 此函数不保证准确性,在重载条件下,应⽤程序的休眠时间可能超过⼏秒
usleep()
:强制当前线程休眠数秒(微秒)- 此函数不保证准确性,在重载条件下,应⽤程序的休眠时间可能超过⼏秒
requestInterruption()
:请求线程的中断- 该请求是咨询性的,由线程上运⾏的代码决定是否以及如何对此类请求采取⾏动
- 此函数不会停⽌线程上运⾏的任何事件循环,也不会以任何⽅式终⽌线程
run()
:线程的起点,调⽤start()
后,新创建的线程调⽤此函数quit()
:告诉线程的事件循环以返回码0(success)退出,相当于调⽤QThread::exit(0)
wait()
:阻塞线程,直到满⾜以下任何⼀个条件:- 与此
QThread
对象关联的线程已经完成执⾏(即当它从run()
返回时)- 如果线程已经完成,这个函数将返回
true
- 如果线程尚未启动,它也返回
true
- 如果线程已经完成,这个函数将返回
- 已经过了⼏毫秒
- 如果时间是
ULONG_MAX
(默认值),那么等待永远不会超时(线程必须从run()
返回) - 如果等待超时,此函数将返回
false
- 如果时间是
- 这提供了与POSIX
pthread_join()
函数类似的功能
- 与此
start()
:通过调⽤run()
开始执⾏线程,OS将根据优先级参数调度线程- 如果线程已经在运⾏,这个函数什么也不做
terminate()
:终⽌线程的执⾏- 线程可以⽴即终⽌,也可以不⽴即终⽌,这取决于OS的调度策略
- 在
terminate()
之后使⽤QThread::wait()
来确保
finished()
:当线程结束时会发出该信号,可以通过该信号来实现线程的清理⼯作
2.线程同步工具
0.简介
- 线程并⾏会导致资源竞争,线程同步⼯具会解决这些冲突
- 实现线程互斥和同步常⽤的类有:
- 互斥锁:
QMutex
、QMutexLocker
- 条件变量:
QWaitCondition
- 信号量:
QSemaphore
- 读写锁:
QReadLocker
、QWriteLocker
、QReadWriteLock
- 互斥锁:
1.互斥锁
- 互斥锁是⼀种保护和防⽌多个线程同时访问同⼀对象实例的⽅法
- 把多个线程要访问的公共资源,通过锁保护起来 --> 把并发执行变成串行执行
- Qt中,互斥锁主要是通过
QMutex
类来处理
QMutex
:- 特点:⽤于保护共享资源的访问,实现线程间的互斥操作
- ⽤途:在多线程环境下,通过互斥锁来控制对共享数据的访问,确保线程安全
- 示例:
QMutex mutex; mutex.lock(); // 上锁 // 访问共享资源 mutex.unlock(); // 解锁
QMutexLocker
:- 特点:
QMutexLocker
是QMutex
的辅助类,使⽤RAII⽅式对互斥锁进⾏上锁和解锁操作 - ⽤途:简化对互斥锁的上锁和解锁操作,避免忘记解锁导致的死锁等问题
- 示例:
QMutex mutex; { QMutexLocker locker(mutex); // 在作用域内自动上锁 // 访问临界资源 } // 出作用域自动解锁
- 特点:
QReadWriteLocker
、QReadLocker
、QWriteLocker
:- 特点:
QReadWriteLock
:读写锁类,⽤于控制读和写的并发访问QReadLocker
:⽤于读操作上锁,允许多个线程同时读取共享资源QWriteLocker
:⽤于写操作上锁,只允许⼀个线程写⼊共享资源
- 用途:在某些情况下,多个线程可以同时读取共享数据,但只有⼀个线程能够进⾏写操作
- 读写锁提供了更⾼效的并发访问⽅式
- 示例:
QReadWriteLock rwLock; // 在读操作中使⽤读锁 { QReadLocker locker(&rwLock); // 在作⽤域内⾃动上读锁 // 读取共享资源 }// 在作⽤域结束时⾃动解读锁 // 在写操作中使⽤写锁 { QWriteLocker locker(&rwLock); // 在作⽤域内⾃动上写锁 // 修改共享资源 }// 在作⽤域结束时⾃动解写锁
- 特点:
2.信号量
- 有时在多线程编程中,需要确保多个线程可以相应的访问⼀个数量有限的相同资源
- 信号量类似于增强的互斥锁,不仅能完成上锁和解锁操作,⽽且可以跟踪可⽤资源的数量
- 特点:
QSemaphore
是Qt框架提供的计数信号量类,⽤于控制同时访问共享资源的线程数量 - ⽤途:限制并发线程数量,⽤于解决⼀些资源有限的问题
- 示例:
QSemaphore semaphore(2); // 同时允许两个线程访问共享资源 // 在需要访问共享资源的线程中 semaphore.acquire(); // 尝试获取信号量,若已满则阻塞 // 访问共享资源 semaphore.release(); // 释放信号量 // 在另⼀个线程中进⾏类似操作
3.条件变量
- 在多线程编程中,假设除了等待OS正在执⾏的线程之外,某个线程还必须等待某些条件满⾜才能执⾏,这时就会出现问题
- 这种情况下,线程会很⾃然地使⽤锁的机制来阻塞其他线程
- 因为这只是线程的轮流使⽤,并且该线程等待某些特定条件
- ⼈们会认为需要等待条件的线程,在释放互斥锁或读写锁之后进⼊了睡眠状态
- 这样其他线程就可以继续运⾏,当条件满⾜时,等待条件的线程将被另⼀个线程唤醒
- 在Qt中,专⻔提供了
QWaitCondition
类来解决上述这样的问题- 多个线程之间的调度是无序的,为了一定程度的干预线程之间的执行顺序,引入条件变量
- 特点:
QWaitCondition
是Qt框架提供的条件变量类,⽤于线程之间的消息通信和同步 - ⽤途:在某个条件满⾜时等待或唤醒线程,⽤于线程的同步和协调
- 示例:
QMutex mutex; QWaitCondition condition; --------------------------------------------------------------- // 在等待线程中 mutex.lock(); // 检查条件是否满⾜,若不满⾜则等待 while (!conditionFullfilled()) { condition.wait(&mutex); // 等待条件满⾜并释放锁 } // 条件满⾜后继续执⾏ mutex.unlock(); --------------------------------------------------------------- // 在改变条件的线程中 mutex.lock(); // 改变条件 changeCondition(); condition.wakeAll(); // 唤醒等待的线程 mutex.unlock();