【问题标题】:Settings and accessing a pointer from concurrent goroutines设置和访问来自并发 goroutine 的指针
【发布时间】:2014-05-29 05:54:06
【问题描述】:

我有一张地图,供 goroutine A 使用,并在 goroutine B 中一次替换一次。我的意思是:

var a map[T]N

// uses the map
func goroutineA() {
    for (...) {
        tempA = a
        ..uses tempA in some way...
    }
}

//refreshes the map
func gorountineB() {
    for (...) {
        time.Sleep(10 * time.Seconds)
        otherTempA = make(map[T]N)
        ...initializes other tempA....
        a = otherTempA 
    }
}

你觉得这个伪代码有什么问题吗? (就并发而言)

【问题讨论】:

    标签: go


    【解决方案1】:

    代码不安全,因为不能保证对指针值的赋值和读取是原子的。这可能意味着当一个 goroutine 写入新的指针值时,另一个可能会看到来自旧值和新值的字节混合,这将导致您的程序以一种令人讨厌的方式死掉。可能发生的另一件事是,由于您的代码中没有同步,编译器可能会注意到 goroutineA 中的 a 没有任何变化,并将tempA := a 语句从循环中取出。这意味着当其他 goroutine 更新它们时,您将永远不会看到新的地图分配。

    您可以使用go test -race 自动查找此类问题。

    一种解决方案是使用互斥锁锁定对地图的所有访问。

    您可能希望阅读Go Memory Model 文档,该文档清楚地解释了变量的更改何时在 goroutine 中可见。

    【讨论】:

      【解决方案2】:

      如果不确定数据竞赛,请运行go run -race file.go,话虽如此,是的,会有竞赛。

      解决这个问题的最简单方法是使用sync.RWMutex

      var a map[T]N
      var lk sync.RWMutex
      // uses the map
      func goroutineA() {
          for (...) {
              lk.RLock()
              //actions on a
              lk.RUnlock()
          }
      }
      
      //refreshes the map
      func gorountineB() {
          for (...) {
              otherTempA = make(map[T]N)
              //...initializes other tempA....
              lk.Lock()
              a = otherTempA
              lk.Unlock()
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2013-08-09
        • 2021-03-02
        • 1970-01-01
        • 2013-11-23
        • 1970-01-01
        • 1970-01-01
        • 2014-04-19
        • 2016-06-16
        • 1970-01-01
        相关资源
        最近更新 更多