在Rust中,设计一个线程安全的栈结构Stack<T>
,类似于Channel<T>
,但使用栈的FILO(First-In-Last-Out)原则来在线程间传送数据,可以通过使用标准库中的同步原语如Mutex
和Condvar
来实现。下面是一个简单的实现示例:
use std::collections::VecDeque;
use std::sync::{Mutex, Condvar};
use std::thread;
use std::time::Duration;
pub struct Stack<T> {
data: Mutex<VecDeque<T>>,
not_empty: Condvar,
}
impl<T> Stack<T> {
pub fn new() -> Stack<T> {
Stack {
data: Mutex::new(VecDeque::new()),
not_empty: Condvar::new(),
}
}
pub fn push(&self, item: T) {
let mut data = self.data.lock().unwrap();
data.push_front(item);
self.not_empty.notify_one();
}
pub fn pop(&self) -> Option<T> {
let mut data = self.data.lock().unwrap();
while data.is_empty() {
data = self.not_empty.wait(data).unwrap().0;
}
data.pop_back()
}
}
// 示例用法
fn main() {
let stack = Stack::new();
let producer = thread::spawn(move || {
for i in 1..=5 {
stack.push(i);
println!("Produced {}", i);
thread::sleep(Duration::from_millis(500));
}
});
let consumer = thread::spawn(move || {
while let Some(item) = stack.pop() {
println!("Consumed {}", item);
}
});
producer.join().unwrap();
consumer.join().unwrap();
}
在这个示例中,Stack<T>
结构包含了一个受互斥锁保护的VecDeque<T>
,它用作底层的数据存储。VecDeque
是一个双端队列,但在这里我们只使用其作为栈的功能,通过push_front
和pop_back
方法来模拟栈的行为。not_empty
是一个条件变量,用于在栈为空时阻塞消费者线程,直到有数据可用。
在push
方法中,我们将数据项推入栈中,并通过notify_one
方法唤醒一个等待的消费者线程(如果有的话)。在pop
方法中,我们检查栈是否为空,并在为空时使用wait
方法阻塞当前线程,直到有数据被推入栈中。当栈不为空时,我们从栈中弹出一个数据项并返回它。
在示例的main
函数中,我们创建了一个Stack<i32>
实例,并启动了一个生产者线程和一个消费者线程。生产者线程将数字1到5推入栈中,每次推送后休眠500毫秒。消费者线程则不断地从栈中弹出数据项,并打印它们,直到栈为空为止。