设计思路
- 选用同步原语:使用
Mutex
来保护双端队列的数据结构,确保同一时间只有一个线程能访问队列。同时,使用Condvar
来处理线程等待和唤醒,以实现高效的线程同步。
- 处理竞态条件:在对双端队列进行插入和删除操作时,通过
Mutex
加锁来防止多个线程同时修改队列,避免数据竞争。当队列为空且有线程尝试取出元素时,使用Condvar
让线程进入等待状态,直到队列中有新元素被插入。
- 优化性能:尽量缩小锁的粒度,只在对队列进行修改操作时加锁。对于读取操作,如果不需要保证绝对一致性,可以考虑使用
RwLock
来允许多个线程同时读。此外,可以使用parking_lot
库中的Mutex
和Condvar
,它们在性能上比标准库中的同类产品更优。
Rust代码实现
use std::sync::{Arc, Mutex, Condvar};
use std::collections::VecDeque;
pub struct ThreadSafeDeque<T> {
inner: Arc<(Mutex<VecDeque<T>>, Condvar)>,
}
impl<T> ThreadSafeDeque<T> {
pub fn new() -> Self {
ThreadSafeDeque {
inner: Arc::new((Mutex::new(VecDeque::new()), Condvar::new())),
}
}
pub fn push_front(&self, value: T) {
let (lock, cvar) = &*self.inner;
let mut queue = lock.lock().unwrap();
queue.push_front(value);
cvar.notify_one();
}
pub fn push_back(&self, value: T) {
let (lock, cvar) = &*self.inner;
let mut queue = lock.lock().unwrap();
queue.push_back(value);
cvar.notify_one();
}
pub fn pop_front(&self) -> Option<T> {
let (lock, cvar) = &*self.inner;
let mut queue = lock.lock().unwrap();
while queue.is_empty() {
queue = cvar.wait(queue).unwrap();
}
queue.pop_front()
}
pub fn pop_back(&self) -> Option<T> {
let (lock, cvar) = &*self.inner;
let mut queue = lock.lock().unwrap();
while queue.is_empty() {
queue = cvar.wait(queue).unwrap();
}
queue.pop_back()
}
}
代码解释
- 结构体定义:
ThreadSafeDeque
结构体包含一个Arc
,内部封装了一个元组,元组的第一个元素是Mutex<VecDeque<T>>
,用于保护双端队列,第二个元素是Condvar
,用于线程间的同步。
- 构造函数:
new
函数用于创建一个新的ThreadSafeDeque
实例,初始化内部的VecDeque
。
- 入队操作:
push_front
和push_back
函数在双端队列的前端和后端插入元素。首先获取Mutex
的锁,插入元素后,通过Condvar
唤醒一个等待的线程(如果有)。
- 出队操作:
pop_front
和pop_back
函数从双端队列的前端和后端取出元素。如果队列为空,线程会通过Condvar
进入等待状态,直到被唤醒。当队列中有元素时,取出并返回元素。