【问题标题】:How can we use channels in Go in place of mutex?我们如何在 Go 中使用通道来代替互斥锁?
【发布时间】:2011-04-26 12:11:59
【问题描述】:

通道将通信(值的交换)与同步相结合,确保两个计算(goroutines)处于已知状态。

如何使用 Google Go 中的通道来执行互斥锁的功能?

package main

import "sync"

var global int = 0
var m sync.Mutex

func thread1(){
    m.Lock()
    global = 1
    m.Unlock()
}

func thread2(){
    m.Lock()
    global = 2
    m.Unlock()
}

func main(){
   go thread1()
   go thread2()
}

【问题讨论】:

  • 这个问题有点没抓住重点。您应该问自己“我为什么需要互斥锁,以及如何使用通道来代替?”

标签: go goroutine


【解决方案1】:

使用 Channel 作为 Mutex 的示例:

package main

var global int = 0
var c = make(chan int, 1)

func thread1(){
    <-c // Grab the ticket
    global = 1
    c <- 1 // Give it back
}

func thread2(){
    <-c
    global = 2
    c <- 1
}

func main() {
   c <- 1 // Put the initial value into the channel
   go thread1()
   go thread2()
}

您也可以使用chan struct{} 代替chan int 来减少内存大小。进入它的值是struct{}{}(类型struct{} 和一个空的内容{})。示例见Ivan black's comment

【讨论】:

  • 感谢 MizardX 的回答。
  • 虽然通道为受保护的数据提供了一个很好的解决方案,但在一个作者和许多读者的情况下,它的效率较低。
  • 我建议使用chan struct{} 来避免真正的数据发送。 chan struct{} 像信号量一样工作,并且对于任何缓冲区大小在内存中都有相同的大小。例如play.golang.org/p/Ap_f37hSvxf
【解决方案2】:

如果您有一个通道 c,您在其中初始化了 1 个项目,那么您可以通过从通道 (&lt;-c) 中删除值来“签出”“互斥锁”。您可以通过将值加回 (c &lt;- 1) 来“释放”它。

由于从通道中提取操作符 a) 是原子的,并且 b) 阻塞直到有东西要提取,所以它作为一个互斥体工作,因为如果一个执行线程已经检查了它,那么在通道,因此它将阻塞,直到检查它的线程返回一个值给通道以供另一个线程提取。

【讨论】:

  • 谢谢琥珀。我们可以使用通道而不是互斥锁来实现上面显示的示例吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-29
  • 1970-01-01
  • 1970-01-01
  • 2017-12-22
  • 2021-06-21
相关资源
最近更新 更多