Qt 线程同步的方式及数量详解
在 Qt 框架中,线程同步是确保多线程程序正确性和效率的关键。以下是 Qt 提供的线程同步方式及其详细说明:
1. 互斥锁(QMutex)
- 功能:保护共享资源,确保同一时间只有一个线程能访问临界区。
- 核心方法:
lock()
:获取锁,阻塞直至成功。tryLock()
:尝试非阻塞获取锁。unlock()
:释放锁。
- 模式:
- 非递归模式(默认):同一线程重复加锁会导致死锁。
- 递归模式:允许同一线程多次加锁。
- 示例:
QMutex mutex; mutex.lock(); // 临界区代码 mutex.unlock();
2. 读写锁(QReadWriteLock)
- 功能:允许多个线程同时读取共享资源,但写操作互斥。
- 核心方法:
lockForRead()
:获取读锁(共享)。lockForWrite()
:获取写锁(独占)。unlock()
:释放锁。
- 适用场景:读多写少的场景,提升并发性能。
- 示例:
QReadWriteLock lock; lock.lockForRead(); // 多线程可同时读取 // 读操作 lock.unlock(); lock.lockForWrite(); // 仅一个线程可写入 // 写操作 lock.unlock();
3. 信号量(QSemaphore)
- 功能:控制对有限数量资源的访问,类似互斥锁的扩展。
- 核心方法:
acquire(n)
:获取n
个资源(阻塞直至可用)。release(n)
:释放n
个资源。
- 示例:
QSemaphore sem(3); // 允许最多3个线程同时访问 sem.acquire(); // 获取一个资源 // 临界区代码 sem.release(); // 释放资源
4. 条件变量(QWaitCondition)
- 功能:线程等待特定条件满足后被唤醒,通常与
QMutex
配合使用。 - 核心方法:
wait(QMutex *mutex)
:释放锁并阻塞,直至被唤醒。wakeOne()
:唤醒一个等待线程。wakeAll()
:唤醒所有等待线程。
- 示例:
QMutex mutex; QWaitCondition cond; mutex.lock(); cond.wait(&mutex); // 释放锁并等待 mutex.unlock(); // 唤醒线程 cond.wakeOne();
5. 原子操作(QAtomicInt 等)
- 功能:通过硬件保证的原子性操作,适用于简单共享数据(如计数器)。
- 核心类:
QAtomicInt
:原子整数操作。QAtomicPointer
:原子指针操作。
- 示例:
QAtomicInt counter(0); counter.fetchAndAdd(1); // 原子自增
6. 自动锁管理类
- 功能:简化锁的获取和释放,避免死锁。
- QMutexLocker:自动管理
QMutex
。 - QReadLocker/QWriteLocker:自动管理
QReadWriteLock
的读/写锁。
- QMutexLocker:自动管理
- 示例:
void func() { QMutexLocker locker(&mutex); // 自动加锁 // 临界区代码 // 自动解锁(析构时调用) }
7. 事件队列与信号槽机制
- 功能:通过跨线程信号槽连接或
QMetaObject::invokeMethod()
实现线程间通信。 - 特点:
- 队列连接确保槽函数在目标线程的事件循环中执行。
- 避免直接同步的开销,但需手动保护共享数据。
- 示例:
// 信号槽连接(队列模式) connect(thread, &MyThread::signal, receiver, &Receiver::slot, Qt::QueuedConnection); // 跨线程调用方法 QMetaObject::invokeMethod(target, "method", Qt::QueuedConnection);
8. QThread::wait()
- 功能:阻塞当前线程,等待另一个线程结束。
- 注意:需谨慎使用以避免死锁。
- 示例:
QThread thread; thread.start(); // ... thread.wait(); // 阻塞直至线程结束
总结
Qt 提供了 8 种 线程同步方式,涵盖从低级原语(如互斥锁、信号量)到高级机制(如信号槽、事件队列)的全面解决方案。开发者可根据具体场景选择合适的同步方式,平衡安全性与性能。