使用的并发原语
- Mutex(互斥锁):用于保护共享资源,在任何时刻只允许一个线程访问商品库存和订单记录等共享数据。在Rust中,
std::sync::Mutex
提供了这种功能。例如,将商品库存和订单记录包装在 Mutex
中,线程在访问前需要先获取锁。
use std::sync::Mutex;
let stock = Mutex::new(100); // 初始库存100
let order_log = Mutex::new(Vec::new());
- Arc(原子引用计数):用于在多个线程间安全地共享数据。当多个线程需要访问同一个
Mutex
包裹的数据时,Arc
可以用来持有 Mutex
的所有权,从而实现跨线程共享。
use std::sync::{Arc, Mutex};
let shared_stock = Arc::new(Mutex::new(100));
let shared_order_log = Arc::new(Mutex::new(Vec::new()));
- Condvar(条件变量):如果在订单处理过程中有需要等待某个条件满足的情况,比如库存充足时才处理订单,可以使用
Condvar
。它与 Mutex
配合使用,线程可以在条件变量上等待,当条件满足时被唤醒。
use std::sync::{Arc, Condvar, Mutex};
let stock = Arc::new((Mutex::new(100), Condvar::new()));
代码结构设计
- 封装订单处理逻辑:将订单处理操作封装在一个函数或结构体方法中,这样可以将共享资源的访问和操作集中管理。
struct OrderProcessor {
stock: Arc<Mutex<i32>>,
order_log: Arc<Mutex<Vec<String>>>,
}
impl OrderProcessor {
fn process_order(&self, order_amount: i32) {
let mut guard = self.stock.lock().unwrap();
while *guard < order_amount {
guard = self.stock.condvar().wait(guard).unwrap();
}
*guard -= order_amount;
self.stock.unlock();
let mut log_guard = self.order_log.lock().unwrap();
log_guard.push(format!("Order of {} items processed", order_amount));
}
}
- 线程管理:使用
std::thread::spawn
创建线程,并将 OrderProcessor
实例通过 Arc
传递给新线程。
use std::thread;
let processor = OrderProcessor {
stock: Arc::new(Mutex::new(100)),
order_log: Arc::new(Mutex::new(Vec::new())),
};
let handle = thread::spawn(move || {
processor.process_order(10);
});
避免死锁
- 固定锁获取顺序:在涉及多个锁的情况下,确保所有线程以相同的顺序获取锁。例如,如果线程需要同时获取库存锁和订单记录锁,始终先获取库存锁,再获取订单记录锁。
- 超时机制:使用
try_lock
方法尝试获取锁,并设置超时。如果在规定时间内未能获取锁,可以选择放弃操作或采取其他策略,避免无限期等待。
let mut guard = match self.stock.try_lock() {
Ok(guard) => guard,
Err(_) => return, // 获取锁失败,放弃操作
};
- 减少锁持有时间:尽量缩短持有锁的代码块,只在必要的操作时持有锁。例如,在修改库存后立即释放库存锁,然后再进行订单记录操作,以减少死锁风险。