读写锁顾名思义就是只允许单进程同时写,在数据没有被写的情况下允许多进程同时读,的锁。
rust 里和 Mutex 类似,使用RAII(Resource Acquisition Is Initialization)来保证在值被Drop的时候自动解锁。而 go 里依然是需要手动解锁。
举个改写自Go标准库测试的栗子
import (
. "sync"
"sync/atomic"
)
const NumIterations = 1000
const NumReaders = 1000
func writer(rwm *RWMutex, activity *int32, cdone chan bool) {
for i := 0; i < NumIterations; i++ {
rwm.Lock()
n := atomic.AddInt32(activity, 10000)
if n != 10000 {
panic(fmt.Sprintf("wlock(%d)\n", n))
}
atomic.AddInt32(activity, -10000)
rwm.Unlock()
}
cdone <- true
}
func reader(rwm *RWMutex, activity *int32, cdone chan bool) {
for i := 0; i < NumIterations; i++ {
rwm.RLock()
n := atomic.AddInt32(activity, 1)
// 即使只获得了读锁,依旧可以修改数据
// 只是禁止别的进程获取写锁
if n < 1 || n > 10000 {
panic(fmt.Sprintf("wlock(%d)\n", n))
}
atomic.AddInt32(activity, -1)
rwm.RUnlock()
}
cdone <- true
}
func main() {
var activity int32
var rwm sync.RWMutex
cdone := make(chan bool)
go writer(&rwm, &activity, cdone)
var i int
for i = 0; i < NumReaders/2; i++ {
go reader(&rwm, &activity, cdone)
}
go writer(&rwm, &activity, cdone)
for ; i < NumReaders; i++ {
go reader(&rwm, &activity, cdone)
}
for i := 0; i < 2+NumReaders; i++ {
<-cdone
}
}
把上面那个栗子改写成 Rust
use std::sync::mpsc::{channel, Sender};
use std::sync::{Arc, RwLock};
use std::thread;
const NumIterations: usize = 1000;
// 由于直接使用操作系统的 Thread,所以不能开太多
const NumReaders: usize = 500;
fn main() {
let data = Arc::new(RwLock::new(0));
let (tx, rx) = channel();
{
let (data, tx) = (data.clone(), tx.clone());
thread::spawn(move || {
writer(data, tx);
});
}
for _ in 0..NumReaders/2 {
let (data, tx) = (data.clone(), tx.clone());
thread::spawn(move || {
reader(data, tx);
});
}
{
let (data, tx) = (data.clone(), tx.clone());
thread::spawn(move || {
writer(data, tx);
});
}
for _ in NumReaders/2..NumReaders {
let (data, tx) = (data.clone(), tx.clone());
thread::spawn(move || {
reader(data, tx);
});
}
for _ in 0..NumReaders {
rx.recv();
}
}
fn writer(data: Arc<RwLock<i32>>, tx: Sender<bool>) {
for _ in 0..NumIterations {
let mut w = data.write().unwrap();
*w += 10000;
assert!(*w == 10000);
*w -= 10000;
}
tx.send(true);
}
fn reader(data: Arc<RwLock<i32>>, tx: Sender<bool>) {
for _ in 0..NumIterations {
// 只获得读锁是无法写数据的
let r = data.read().unwrap();
assert!(*r == 0);
}
tx.send(true);
}
有疑问加站长微信联系(非本文作者)