不使用互斥锁

huangapple go评论123阅读模式
英文:

Going mutex-less

问题

好的,以下是代码的中文翻译:

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. done := make(chan int)
  7. x := 0
  8. for i := 0; i < 10; i++ {
  9. go func() {
  10. y := next(&x)
  11. fmt.Println(y)
  12. done <- 0
  13. }()
  14. }
  15. for i := 0; i < 10; i++ {
  16. <-done
  17. }
  18. fmt.Println(x)
  19. }
  20. var mutex = make(chan int, 1)
  21. func next(p *int) int {
  22. mutex <- 0
  23. // 临界区开始
  24. x := *p
  25. *p++
  26. // 临界区结束
  27. <-mutex
  28. return x
  29. }

假设不能同时有两个goroutine进入临界区,否则会发生问题。

我第一个猜测是使用一个单独的goroutine来处理状态,但我无法找到一种匹配输入/输出的方法。

英文:

Alright, Go "experts". How would you write this code in idiomatic Go, aka without a mutex in next?

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. )
  5. func main() {
  6. done := make(chan int)
  7. x := 0
  8. for i := 0; i &lt; 10; i++ {
  9. go func() {
  10. y := next(&amp;x)
  11. fmt.Println(y)
  12. done &lt;- 0
  13. }()
  14. }
  15. for i := 0; i &lt; 10; i++ {
  16. &lt;-done
  17. }
  18. fmt.Println(x)
  19. }
  20. var mutex = make(chan int, 1)
  21. func next(p *int) int {
  22. mutex &lt;- 0
  23. // critical section BEGIN
  24. x := *p
  25. *p++
  26. // critical section END
  27. &lt;-mutex
  28. return x
  29. }

Assume you can't have two goroutines in the critical section at the same time, or else bad things will happen.

My first guess is to have a separate goroutine to handle the state, but I can't figure out a way to match up inputs / outputs.

答案1

得分: 3

你可以使用实际的sync.Mutex:

  1. var mutex sync.Mutex
  2. func next(p *int) int {
  3. mutex.Lock()
  4. defer mutex.Unlock()
  5. x := *p
  6. *p++
  7. return x
  8. }

不过,你可能还会将next功能、状态和sync.Mutex组合成一个单一的结构体。

虽然在这种情况下没有理由这样做,因为Mutex更适合用于互斥访问单个资源,但你可以使用goroutines和channels来实现相同的效果。

  1. x := 0
  2. var wg sync.WaitGroup
  3. send := make(chan *int)
  4. recv := make(chan int)
  5. go func() {
  6. for i := range send {
  7. x := *i
  8. *i++
  9. recv <- x
  10. }
  11. }()
  12. for i := 0; i < 10; i++ {
  13. wg.Add(1)
  14. go func() {
  15. defer wg.Done()
  16. send <- &x
  17. fmt.Println(<-recv)
  18. }()
  19. }
  20. wg.Wait()
  21. fmt.Println(x)

你可以在这里查看示例代码:http://play.golang.org/p/RR4TQXf2ct

英文:

You would use an actual sync.Mutex:

  1. var mutex sync.Mutex
  2. func next(p *int) int {
  3. mutex.Lock()
  4. defer mutex.Unlock()
  5. x := *p
  6. *p++
  7. return x
  8. }

Though you would probably also group the next functionality, state and sync.Mutex into a single struct.

Though there's no reason to do so in this case, since a Mutex is better suited for mutual exclusion around a single resource, you can use goroutines and channels to achieve the same effect

http://play.golang.org/p/RR4TQXf2ct

  1. x := 0
  2. var wg sync.WaitGroup
  3. send := make(chan *int)
  4. recv := make(chan int)
  5. go func() {
  6. for i := range send {
  7. x := *i
  8. *i++
  9. recv &lt;- x
  10. }
  11. }()
  12. for i := 0; i &lt; 10; i++ {
  13. wg.Add(1)
  14. go func() {
  15. defer wg.Done()
  16. send &lt;- &amp;x
  17. fmt.Println(&lt;-recv)
  18. }()
  19. }
  20. wg.Wait()
  21. fmt.Println(x)

答案2

得分: 1

如@favoretti所提到的,sync/atomic是一种实现的方法。

但是,你必须使用int32或int64而不是int(因为int在不同的平台上可能有不同的大小)。

这里有一个在Playground上的示例:

  1. package main
  2. import (
  3. "fmt"
  4. "sync/atomic"
  5. )
  6. func main() {
  7. done := make(chan int)
  8. x := int64(0)
  9. for i := 0; i < 10; i++ {
  10. go func() {
  11. y := next(&x)
  12. fmt.Println(y)
  13. done <- 0
  14. }()
  15. }
  16. for i := 0; i < 10; i++ {
  17. <-done
  18. }
  19. fmt.Println(x)
  20. }
  21. func next(p *int64) int64 {
  22. return atomic.AddInt64(p, 1) - 1
  23. }
英文:

As @favoretti mentioned, sync/atomic is a way to do it.

But, you have to use int32 or int64 rather than int (since int can be different sizes on different platforms).

Here's an example on Playground

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;sync/atomic&quot;
  5. )
  6. func main() {
  7. done := make(chan int)
  8. x := int64(0)
  9. for i := 0; i &lt; 10; i++ {
  10. go func() {
  11. y := next(&amp;x)
  12. fmt.Println(y)
  13. done &lt;- 0
  14. }()
  15. }
  16. for i := 0; i &lt; 10; i++ {
  17. &lt;-done
  18. }
  19. fmt.Println(x)
  20. }
  21. func next(p *int64) int64 {
  22. return atomic.AddInt64(p, 1) - 1
  23. }

huangapple
  • 本文由 发表于 2015年9月26日 17:46:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/32795785.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定