10.5.1 sync.Mutex类型

sync.Mutex 类型是 Go 实现的一个互斥体。它的定义可以在 sync 目录的 mutex.go 文件中找到,内容如下:

sync.Mutex 类型的定义没有什么特别的。所有的工作都是由 sync.Lock()sync.Unlock() 来做的,它们分别能加锁和解锁 sync.Mutex 互斥体。给互斥体上锁意味着没人可以操作它,直到使用 sync.Unlock() 函数解锁。

mutex.go 程序分为五部分介绍,来说明 sync.Mutex 类型的使用。

mutex.go 的第一段代码如下:

package main

import (
    "fmt"
    "os"
    "strconv"
    "sync"
    "time"
)

var (
    m sync.Mutex
    v1 int
)

mutex.go 的第二段代码如下:

func change(i int) {
    m.Lock()
    time.Sleep(time.Second)
    v1 = v1 + 1
    if v1 % 10 == 0 {
        v1 = v1 - 10*i
    }
    m.Unlock()
}

这个函数的关键部分是 m.Lock()m.Unlock() 之间的代码。

mutex.go 的第三部分如下:

func read() int {
    m.Lock()
    a := v1
    m.Unlock()
    return a
}

同样,这个函数的关键部分也由 m.Lock()m.Unlock() 表达式限定。

mutex.go 的第四部分代码如下:

func main() {
    if len(os.Args) != 2 {
        fmt.Println("Please give me an integer!")
        return
    }

    numGR, err := strconv.Atoi(os.Args[1])
    if err != nil {
        fmt.Println(err)
        return
    }
    var waitGroup sync.WaitGroup

mutex.go 的最后一段代码如下:

    fmt.Printf("%d ", read())
    for i := 0; i < numGR; i++ {
        waitGroup.Add(1)
        go func(i int) {
            defer waitGroup.Done()
            change(i)
            fmt.Printf("-> %d", read())
        }(i)
    }

    waitGroup.Wait()
    fmt.Printf("-> %d\n", read())
}

执行 mutex.go 将产生如下输出:

如果您从 change() 函数移除 m.Lock()m.Unlock() 表达式,这个程序会产生类似如下输出:

输出中发生改变的原因是所有 goroutines 同时去修改共享变量,这也是随机输出的主要原因。

Last updated