Rust中的mutex与other language的mutex对比

直接上代码:

GO

先上靶子来批判。

package main
import (
    "fmt"
    "time"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    var(
        mt sync.Mutex
        a string
    )
    a =  "I am in Main thread"


    wg.Add(1)
    go func() {
        mt.Lock()
        a =  "I am in Sub-thread"
        fmt.Printf("**SUB** thread  [1]: %v \n", a)
        time.Sleep(3 * time.Second)
        fmt.Printf("**SUB** thread  [2]: %v \n", a)
        mt.Unlock()
        wg.Done()
    } ();
    time.Sleep(time.Second)
    a =  "I am in Main thread"
    fmt.Printf("**MAIN** thread [3]: %v \n", a)
    wg.Wait()
}

expected result:

➜  tmp git:(master) ✗ go run mutex_error_using.go
**SUB** thread  [1]: I am in Sub-thread 
**SUB** thread  [2]: I am in Sub-thread 
**MAIN** thread [3]: I am in Main thread 

running result:

➜  tmp git:(master) ✗ go run mutex_error_using.go
**SUB** thread  [1]: I am in Sub-thread 
**MAIN** thread [3]: I am in Main thread 
**SUB** thread  [2]: I am in Main thread 

预期是通过加锁使得子线程临界区(Lock,Unlock之间的内容被锁上)。通过观察可以发现[3]这里直接修改a的值。使得子线程里第二次获取到的a的值是修改过的,与我们想象的结果有出入。这是因为go里的锁,就只是一个提示作用,怎么用还得看程序员。我们没有去获取锁的状态,直接修改了临界区内的值在编译器看来也是合理的。虽然这是一个很低级的错误,但是当碰上较大的工程的时候,所有人都有可能写出上面的代码。

Rust

use std::sync::Mutex;
fn main() {
    let m = Mutex::new(5);
    {
        let mut num = m.lock().unwrap();
        *num = 6;
    }
    println!("m is {:?}",m);
}

而Rust就不一样了,直接把要改变的值包在了Mutex里,无法绕开Mutex直接去改写里边的值。程序员就没法写出类似GO那种绕开锁的代码。