sync.Mutex 类型

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

""

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

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

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

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "strconv"
  6. "sync"
  7. "time"
  8. )
  9. var (
  10. m sync.Mutex
  11. v1 int
  12. )

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

  1. func change(i int) {
  2. m.Lock()
  3. time.Sleep(time.Second)
  4. v1 = v1 + 1
  5. if v1 % 10 == 0 {
  6. v1 = v1 - 10*i
  7. }
  8. m.Unlock()
  9. }

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

mutex.go 的第三部分如下:

  1. func read() int {
  2. m.Lock()
  3. a := v1
  4. m.Unlock()
  5. return a
  6. }

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

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

  1. func main() {
  2. if len(os.Args) != 2 {
  3. fmt.Println("Please give me an integer!")
  4. return
  5. }
  6. numGR, err := strconv.Atoi(os.Args[1])
  7. if err != nil {
  8. fmt.Println(err)
  9. return
  10. }
  11. var waitGroup sync.WaitGroup

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

  1. fmt.Printf("%d ", read())
  2. for i := 0; i < numGR; i++ {
  3. waitGroup.Add(1)
  4. go func(i int) {
  5. defer waitGroup.Done()
  6. change(i)
  7. fmt.Printf("-> %d", read())
  8. }(i)
  9. }
  10. waitGroup.Wait()
  11. fmt.Printf("-> %d\n", read())
  12. }

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

""

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

""

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