經過例子來學習 Go 和 Rust ---- RwLock 讀寫鎖

讀寫鎖顧名思義就是隻容許單進程同時寫,在數據沒有被寫的狀況下容許多進程同時讀,的鎖。測試

rust 裏和 Mutex 相似,使用RAII(Resource Acquisition Is Initialization)來保證在值被Drop的時候自動解鎖。而 go 裏依然是須要手動解鎖。ui

舉個改寫自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);
}
相關文章
相關標籤/搜索