GO:缺乏同步

var a string
var done bool

func setup() {
    a = "hello, world"
    done = true
}

func doprint() {
    if !done {
        once.Do(setup)
    }
    print(a)
}

func twoprint() {
    go doprint()
    go doprint()
}

代码分析

**变量:**

  • a 和 b 是 int 类型的全局变量,被所有 goroutine 共享。
  • **功能:**

  • f():依次写入 a 和 b(a = 1 和 b = 2)。
  • g():
  • 读取并打印 b,然后打印 a。
  • **main() 中的并发:**

  • 函数 f() 使用 go f() 作为单独的 goroutine 执行。
  • 函数 g() 直接在主 goroutine 中执行。
  • **潜在问题:**

  • 运行 f() 的 goroutine 和执行 g() 的主 goroutine 同时运行。
  • 在 g() 读取并打印 a 和 b 的值之前,f() 对 a 和 b 的写入可能尚未完成。
  • 这就引入了数据竞争,其中并发访问(在 f() 中写入并在 g() 中读取)发生在共享内存(a 和 b)上而没有同步。
  • **可能的结果**

    由于缺乏同步,程序的输出是不确定的。以下是可能的情况:

  • a 和 b 的初始值为 0(Go 中未初始化 int 的默认值)。
  • 0
    0

    或者

    2
    0

    **主要观察**

    数据竞争:在没有同步的情况下并发访问 a 和 b 会引入数据竞争。这会使程序的行为变得不确定且不可预测

    **修复代码**

  • 使用 sync.WaitGroup:确保 f() 在 g() 执行之前完成
  • var a, b int
    var wg sync.WaitGroup
    
    func f() {
        a = 1
        b = 2
        wg.Done()
    }
    
    func g() {
        print(b)
        print(a)
    }
    
    func main() {
        wg.Add(1)
        go f()
        wg.Wait()
        g()
    }
  • 使用通道:f() 完成时发出信号:
  • var a, b int
    
    func f(done chan bool) {
        a = 1
        b = 2
        done <- true
    }
    
    func g() {
        print(b)
        print(a)
    }
    
    func main() {
        done := make(chan bool)
        go f(done)
        <-done
        g()
    }

    这里,g() 等待直到 f() 通过 done 通道发送信号。