伪代码实现
// 定义缓冲区大小
const int bufferSize = 10;
// 缓冲区
int buffer[bufferSize];
// 缓冲区索引
int in = 0;
int out = 0;
// 互斥锁
Mutex mutex;
// 条件变量
ConditionVariable notFull;
ConditionVariable notEmpty;
// 生产者线程函数
void Producer() {
while (true) {
int data = generateData();
mutex.lock();
while ((in + 1) % bufferSize == out) {
notFull.wait(mutex);
}
buffer[in] = data;
in = (in + 1) % bufferSize;
notEmpty.signal();
mutex.unlock();
}
}
// 消费者线程函数
void Consumer() {
while (true) {
mutex.lock();
while (in == out) {
notEmpty.wait(mutex);
}
int data = buffer[out];
out = (out + 1) % bufferSize;
notFull.signal();
mutex.unlock();
processData(data);
}
}
可能出现的竞态条件及避免方法
- 竞态条件:
- 多个线程同时访问和修改缓冲区的索引
in
和 out
可能导致数据不一致。例如,当生产者线程和消费者线程同时尝试更新 in
或 out
时,可能会丢失更新。
- 缓冲区状态判断与实际操作之间可能存在时间差。比如,在判断缓冲区不满后,还没来得及放入数据,其他线程可能已经改变了缓冲区状态。
- 避免方法:
- 使用互斥锁
mutex
来保护对缓冲区以及相关索引 in
和 out
的访问。在访问这些共享资源前加锁,访问结束后解锁,确保同一时间只有一个线程能操作共享资源。
- 使用条件变量
notFull
和 notEmpty
来处理线程的等待和唤醒。在判断缓冲区状态(满或空)后,如果不满足条件,线程通过条件变量等待,避免无效的循环检查,同时防止在等待期间其他线程改变缓冲区状态而错过机会。当状态改变满足条件时,通过条件变量唤醒等待的线程。