Go中如何使用通道安全同步数据

How to use channels to safely synchronise data in Go

下面是一个如何使用互斥锁来安全访问数据的例子。我如何使用 CSP (communication sequential processes) 而不是使用互斥锁和解锁来做同样的事情?

type Stack struct {
  top    *Element
  size   int
  sync.Mutex
}

func (ss *Stack) Len() int {
  ss.Lock()
  size := ss.size
  ss.Unlock()
  return size

}

func (ss *Stack) Push(value interface{}) {
  ss.Lock()
  ss.top = &Element{value, ss.top}
  ss.size++
  ss.Unlock()
}

func (ss *SafeStack) Pop() (value interface{}) {
  ss.Lock()
  size := ss.size
  ss.Unlock()
  if size > 0 {
    ss.Lock()
    value, ss.top = ss.top.value, ss.top.next
    ss.size--
    ss.Unlock()
    return
  }

  return nil
}

如果您真的想看看 Go 是如何实现通道的,您基本上会看到一个数组周围的互斥体,以及一些额外的线程处理来阻止执行,直到值被传递。通道的工作是轻松地将数据从内存中的一个位置移动到另一个位置。因此,在你有锁和解锁的地方,你会有这样的例子:

func example() {
    resChan := make(int chan)
    go func(){
        resChan <- 1
    }()
    go func(){
        res := <-resChan
    }
}

所以在示例中,第一个goroutine在发送值后被阻塞,直到第二个goroutine从通道读取。

要在 Go 中使用互斥锁执行此操作,可以使用 sync.WaitGroup 将在设置值时向组中添加一个,然后将其从组中释放,第二个 goroutine 将锁定然后解锁该值.

你的例子中的奇怪之处是 1 没有 goroutines,所以这一切都发生在一个主 goroutine 中,并且锁的使用更传统(就像在 c 线程中一样)所以通道不会真正完成任何事情。您的示例将被视为反模式,就像 golang 谚语所说 "Don't communicate by sharing memory, share memory by communicating."