一、线程同步
用于协调多个线程对共享资源的访问,避免竞态条件。
常用工具:
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多线程应用。