不使用互斥锁

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

Going mutex-less

问题

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

package main

import (
	"fmt"
)

func main() {
	done := make(chan int)
	x := 0
	for i := 0; i < 10; i++ {
		go func() {
			y := next(&x)
			fmt.Println(y)
			done <- 0
		}()
	}
	for i := 0; i < 10; i++ {
		<-done
	}
	fmt.Println(x)

}

var mutex = make(chan int, 1)

func next(p *int) int {
	mutex <- 0
	// 临界区开始
	x := *p
	*p++
	// 临界区结束
	<-mutex
	return x

}

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

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

英文:

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

package main

import (
	&quot;fmt&quot;
)

func main() {
	done := make(chan int)
	x := 0
	for i := 0; i &lt; 10; i++ {
		go func() {
			y := next(&amp;x)
			fmt.Println(y)
			done &lt;- 0
		}()
	}
	for i := 0; i &lt; 10; i++ {
		&lt;-done
	}
	fmt.Println(x)

}

var mutex = make(chan int, 1)

func next(p *int) int {
	mutex &lt;- 0
    // critical section BEGIN
	x := *p
	*p++
    // critical section END
	&lt;-mutex
	return x

}

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:

var mutex sync.Mutex

func next(p *int) int {
    mutex.Lock()
    defer mutex.Unlock()
    x := *p
    *p++
    return x
}

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

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

x := 0

var wg sync.WaitGroup
send := make(chan *int)
recv := make(chan int)

go func() {
    for i := range send {
        x := *i
        *i++
        recv <- x
    }
}()

for i := 0; i < 10; i++ {
    wg.Add(1)
    go func() {
        defer wg.Done()
        send <- &x
        fmt.Println(<-recv)
    }()
}
wg.Wait()
fmt.Println(x)

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

英文:

You would use an actual sync.Mutex:

var mutex sync.Mutex

func next(p *int) int {
	mutex.Lock()
	defer mutex.Unlock()
	x := *p
	*p++
	return x
}

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

x := 0

var wg sync.WaitGroup
send := make(chan *int)
recv := make(chan int)

go func() {
	for i := range send {
		x := *i
		*i++
		recv &lt;- x
	}
}()

for i := 0; i &lt; 10; i++ {
	wg.Add(1)
	go func() {
		defer wg.Done()
		send &lt;- &amp;x
		fmt.Println(&lt;-recv)
	}()
}
wg.Wait()
fmt.Println(x)

答案2

得分: 1

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

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

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

package main

import (
	"fmt"
	"sync/atomic"
)

func main() {
	done := make(chan int)
	x := int64(0)
	for i := 0; i < 10; i++ {
		go func() {
			y := next(&x)
			fmt.Println(y)
			done <- 0
		}()
	}
	for i := 0; i < 10; i++ {
		<-done
	}
	fmt.Println(x)

}

func next(p *int64) int64 {
	return atomic.AddInt64(p, 1) - 1
}
英文:

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

package main

import (
	&quot;fmt&quot;
	&quot;sync/atomic&quot;
)

func main() {
	done := make(chan int)
	x := int64(0)
	for i := 0; i &lt; 10; i++ {
		go func() {
			y := next(&amp;x)
			fmt.Println(y)
			done &lt;- 0
		}()
	}
	for i := 0; i &lt; 10; i++ {
		&lt;-done
	}
	fmt.Println(x)

}

func next(p *int64) int64 {
	return atomic.AddInt64(p, 1) - 1
}

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:

确定