下面是一个使用Qt的 QWaitCondition
的完整示例工程,展示如何实现生产者-消费者模型。生产者生成数据,消费者在数据可用时处理数据:
// main.cpp
#include <QCoreApplication>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QDebug>
#include <cstdlib>
// 共享数据结构
class SharedData {
public:
static const int BUFFER_SIZE = 5;
SharedData() : usedSlots(0) {}
int buffer[BUFFER_SIZE];
int usedSlots; // 当前缓冲区中的数据数量
int produceIndex = 0;
int consumeIndex = 0;
QMutex mutex;
QWaitCondition bufferFull; // 缓冲区满时等待的条件
QWaitCondition bufferEmpty; // 缓冲区空时等待的条件
};
// 生产者线程
class Producer : public QThread {
public:
Producer(SharedData* data, QObject* parent = nullptr)
: QThread(parent), sharedData(data) {}
protected:
void run() override {
for (int i = 0; i < 15; ++i) { // 生产15个数字
sharedData->mutex.lock();
// 如果缓冲区满则等待
while (sharedData->usedSlots == SharedData::BUFFER_SIZE) {
qDebug() << ">>>>> 缓冲区满,生产者等待...";
sharedData->bufferFull.wait(&sharedData->mutex);
}
// 生产数据
int num = rand() % 100;
sharedData->buffer[sharedData->produceIndex] = num;
sharedData->produceIndex = (sharedData->produceIndex + 1) % SharedData::BUFFER_SIZE;
sharedData->usedSlots++;
qDebug() << "生产者添加: " << num << " | 缓冲区大小:" << sharedData->usedSlots;
// 通知消费者缓冲区不为空
sharedData->bufferEmpty.wakeAll();
sharedData->mutex.unlock();
msleep(rand() % 300); // 模拟生产时间
}
}
private:
SharedData* sharedData;
};
// 消费者线程
class Consumer : public QThread {
public:
Consumer(SharedData* data, QObject* parent = nullptr)
: QThread(parent), sharedData(data) {}
protected:
void run() override {
for (int i = 0; i < 15; ++i) { // 消费15个数字
sharedData->mutex.lock();
// 如果缓冲区空则等待
while (sharedData->usedSlots == 0) {
qDebug() << "<<<<< 缓冲区空,消费者等待...";
sharedData->bufferEmpty.wait(&sharedData->mutex);
}
// 消费数据
int num = sharedData->buffer[sharedData->consumeIndex];
sharedData->consumeIndex = (sharedData->consumeIndex + 1) % SharedData::BUFFER_SIZE;
sharedData->usedSlots--;
qDebug() << "消费者获取: " << num << " | 缓冲区大小:" << sharedData->usedSlots;
// 通知生产者缓冲区不满
sharedData->bufferFull.wakeAll();
sharedData->mutex.unlock();
msleep(rand() % 300); // 模拟消费时间
}
}
private:
SharedData* sharedData;
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
qDebug() << "===== 开始生产者-消费者示例 =====";
// 创建共享数据
SharedData sharedData;
// 创建并启动线程
Producer producer(&sharedData);
Consumer consumer(&sharedData);
producer.start();
consumer.start();
// 等待线程完成
producer.wait();
consumer.wait();
qDebug() << "===== 示例结束 =====";
return 0;
}
代码说明:
共享数据结构 (
SharedData
):- 环形缓冲区(大小为5)
QMutex
保护共享资源- 两个
QWaitCondition
:bufferFull
:当缓冲区满时,生产者等待此条件bufferEmpty
:当缓冲区空时,消费者等待此条件
生产者线程:
- 当缓冲区满时调用
bufferFull.wait()
挂起 - 向缓冲区添加随机数字(0-99)
- 添加数据后通过
bufferEmpty.wakeAll()
唤醒消费者
- 当缓冲区满时调用
消费者线程:
- 当缓冲区空时调用
bufferEmpty.wait()
挂起 - 从缓冲区取出数字处理
- 取出数据后通过
bufferFull.wakeAll()
唤醒生产者
- 当缓冲区空时调用
同步机制:
- 使用
while循环检查条件
(避免虚假唤醒) mutex保护
所有共享数据的访问wait()
自动释放互斥锁,唤醒时重新获取
- 使用
运行结果示例:
===== 开始生产者-消费者示例 =====
生产者添加: 67 | 缓冲区大小: 1
消费者获取: 67 | 缓冲区大小: 0
生产者添加: 86 | 缓冲区大小: 1
生产者添加: 44 | 缓冲区大小: 2
<<<<< 缓冲区空,消费者等待...
消费者获取: 86 | 缓冲区大小: 1
生产者添加: 83 | 缓冲区大小: 2
<<<<< 缓冲区空,消费者等待...
消费者获取: 44 | 缓冲区大小: 1
>>>>> 缓冲区满,生产者等待...
消费者获取: 83 | 缓冲区大小: 0
... (更多交替执行的日志) ...
===== 示例结束 =====
编译方法:
- 创建Qt控制台项目 (CONFIG += console)
- 复制上述代码到
main.cpp
- 在
.pro
文件中添加:QT += core concurrent CONFIG += c++11
- 编译运行(确保安装了Qt开发环境)
关键点:
QWaitCondition
必须与QMutex
配合使用- 通过两个独立的condition避免了"死锁"风险
while
循环检查条件保证唤醒后重新验证状态- 环形缓冲区实现了高效的内存复用
这个示例展示了如何使用Qt的同步原语实现线程间安全通信,可直接用于实际项目中任务队列、数据流水线等场景。