一、线程同步
用于协调多个线程对共享资源的访问,避免竞态条件。
常用工具:
-
QMutex(互斥锁)
- 保护临界区,确保一次仅一个线程访问资源。
QMutex mutex; int sharedData = 0;void Thread::run() {mutex.lock();sharedData++; // 安全操作mutex.unlock(); }
- QMutexLocker 自动管理锁生命周期:
{QMutexLocker locker(&mutex);sharedData++; } // 自动解锁
-
QReadWriteLock(读写锁)
- 允许多个读线程,但写线程独占。适用于读多写少的场景。
QReadWriteLock lock; void readData() {lock.lockForRead();// 读取数据lock.unlock(); } void writeData() {lock.lockForWrite();// 修改数据lock.unlock(); }
-
QSemaphore(信号量)
- 控制对多个资源的访问(如连接池)。
QSemaphore sem(3); // 允许3个线程同时访问void accessResource() {sem.acquire();// 使用资源sem.release(); }
-
QWaitCondition(条件变量)
- 实现生产者-消费者模型,线程等待特定条件。
QMutex mutex; QWaitCondition cond; QQueue<int> buffer;void Producer::run() {mutex.lock();buffer.enqueue(data);cond.wakeOne(); // 通知消费者mutex.unlock(); }void Consumer::run() {mutex.lock();while (buffer.isEmpty()) {cond.wait(&mutex); // 等待数据}int data = buffer.dequeue();mutex.unlock(); }
二、异步编程
将耗时操作移至后台线程,避免阻塞主线程(如GUI线程)。
常用方法:
-
信号槽与事件循环
- 通过队列连接(
Qt::QueuedConnection
)跨线程通信。
class Worker : public QObject {Q_OBJECT public slots:void doWork() {// 耗时操作emit resultReady(result);} signals:void resultReady(int); };// 主线程 QThread *thread = new QThread; Worker *worker = new Worker; worker->moveToThread(thread); connect(thread, &QThread::started, worker, &Worker::doWork); connect(worker, &Worker::resultReady, this, &MainWindow::handleResult); thread->start();
- 通过队列连接(
-
QtConcurrent框架
- 简化异步任务执行。
#include <QtConcurrent> void processData(const QImage &image) {// 处理图像 }// 启动异步任务 QFuture<void> future = QtConcurrent::run(processData, image); QFutureWatcher<void> watcher; connect(&watcher, &QFutureWatcher::finished, this, &MainWindow::onFinished); watcher.setFuture(future);
-
异步网络请求(QNetworkAccessManager)
- 非阻塞方式处理HTTP请求。
QNetworkAccessManager *manager = new QNetworkAccessManager(this); connect(manager, &QNetworkAccessManager::finished, this, [](QNetworkReply *reply) {if (reply->error() == QNetworkReply::NoError) {qDebug() << "Data received:" << reply->readAll();} }); manager->get(QNetworkRequest(QUrl("https://example.com")));
三、实际开发建议
-
避免直接操作GUI组件
所有UI更新应在主线程完成,通过信号槽传递结果。 -
资源管理
使用moveToThread
管理对象生命周期,确保对象在正确线程析构。 -
死锁预防
- 按固定顺序获取多个锁。
- 使用
QMutex::tryLock()
设置超时避免永久阻塞。
-
性能优化
- 减少锁的持有时间,避免在临界区执行耗时操作。
- 优先使用无锁结构(如原子操作
QAtomicInt
)。
四、示例场景
场景1:后台计算更新UI
// Worker线程执行计算
class Calculator : public QObject {Q_OBJECT
public slots:void calculate(int input) {int result = 0;for (int i=0; i<input; ++i) result += i;emit done(result);}
signals:void done(int);
};// 主窗口
MainWindow::MainWindow() {QThread *thread = new QThread;Calculator *calc = new Calculator;calc->moveToThread(thread);connect(ui->btn, &QPushButton::clicked, [=] {QtConcurrent::run([=] { calc->calculate(1000000); });});connect(calc, &Calculator::done, this, [=](int res) {ui->label->setText(QString::number(res)); // 主线程更新UI});thread->start();
}
场景2:生产者-消费者模型
// 共享缓冲区
QQueue<Data> buffer;
QMutex mutex;
QWaitCondition bufferNotEmpty;// 生产者
void Producer::run() {while (true) {Data data = generateData();{QMutexLocker locker(&mutex);buffer.enqueue(data);bufferNotEmpty.wakeOne(); // 通知消费者}}
}// 消费者
void Consumer::run() {while (true) {QMutexLocker locker(&mutex);while (buffer.isEmpty()) {bufferNotEmpty.wait(&mutex); // 等待数据}Data data = buffer.dequeue();processData(data);}
}
通过合理选择同步机制和异步模式,可以构建高效、响应迅速的Qt多线程应用。