通过例子来学习 Go 和 Rust ---- RwLock 读写锁

读写锁顾名思义就是只允许单进程同时写,在数据没有被写的情况下允许多进程同时读,的锁。

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>, tx: Sender) {
    for _ in 0..NumIterations {
        let mut w = data.write().unwrap();
        *w += 10000;
        assert!(*w == 10000);
        *w -= 10000;
    }
    tx.send(true);
}

fn reader(data: Arc>, tx: Sender) {
    for _ in 0..NumIterations {
        // 只获得读锁是无法写数据的
        let r = data.read().unwrap();
        assert!(*r == 0);
    }
    tx.send(true);
}

你可能感兴趣的:(golang,rust)