在 Go 中创建一个新的 Mutex 是线程安全的吗?
Is it thread safe to create a new Mutex in Go?
我在 Go 中有一个包含互斥锁的结构,我想确保互斥锁永远不会 nil
。为此,我实现了一个 GetMutex()
函数,它检查互斥量是否为 nil,如果是,则为其赋值。
我的问题是:下面的代码线程安全吗?如果不是,确保 mux
始终被初始化的惯用方法是什么?我唯一能想到的就是在我的 GetMutex()
函数中使用这个包中的全局互斥锁,但也许有不同的方法。
package main
import (
"sync"
)
type Counter struct {
mux *sync.Mutex
counter int
}
// Is this thread safe?
func (c *Counter) GetMux() *sync.Mutex {
if c.mux == nil {
c.mux = &sync.Mutex{}
}
return c.mux
}
func (c *Counter) Inc() {
c.GetMux().Lock()
c.counter++
c.GetMux().Unlock()
}
func main() {
c := &Counter{}
c.Inc()
}
不,如果同时从多个 goroutine 调用 Counter.GetMux()
是不安全的:GetMux()
读取和写入 Counter.mux
字段。
一般方法是使用类似“构造函数”的函数来负责初始化,如下所示:
func NewCounter() *Counter {
return &Counter{
mux: &sync.Mutex{},
}
}
当然,总是用这个 NewCounter()
来创建计数器。
另一种有限的方式是使用 non-pointer 互斥锁值:
type Counter struct {
mux sync.Mutex
counter int
}
所以当你有一个 Counter
结构值时,它在设计上包含一个互斥体。但是如果你这样做,那么 Counter
应该始终用作指针,并且 Counter
结构值不能被复制(否则互斥字段也会被复制,但是作为 [=21 的包文档=] 指出:“不应复制包含此包中定义的类型的值。”).
这样做的明显优势是 Counter
的 zero value 是一个有效且现成的计数器(您应该针对您的自定义类型),并且不需要构造函数。
我在 Go 中有一个包含互斥锁的结构,我想确保互斥锁永远不会 nil
。为此,我实现了一个 GetMutex()
函数,它检查互斥量是否为 nil,如果是,则为其赋值。
我的问题是:下面的代码线程安全吗?如果不是,确保 mux
始终被初始化的惯用方法是什么?我唯一能想到的就是在我的 GetMutex()
函数中使用这个包中的全局互斥锁,但也许有不同的方法。
package main
import (
"sync"
)
type Counter struct {
mux *sync.Mutex
counter int
}
// Is this thread safe?
func (c *Counter) GetMux() *sync.Mutex {
if c.mux == nil {
c.mux = &sync.Mutex{}
}
return c.mux
}
func (c *Counter) Inc() {
c.GetMux().Lock()
c.counter++
c.GetMux().Unlock()
}
func main() {
c := &Counter{}
c.Inc()
}
不,如果同时从多个 goroutine 调用 Counter.GetMux()
是不安全的:GetMux()
读取和写入 Counter.mux
字段。
一般方法是使用类似“构造函数”的函数来负责初始化,如下所示:
func NewCounter() *Counter {
return &Counter{
mux: &sync.Mutex{},
}
}
当然,总是用这个 NewCounter()
来创建计数器。
另一种有限的方式是使用 non-pointer 互斥锁值:
type Counter struct {
mux sync.Mutex
counter int
}
所以当你有一个 Counter
结构值时,它在设计上包含一个互斥体。但是如果你这样做,那么 Counter
应该始终用作指针,并且 Counter
结构值不能被复制(否则互斥字段也会被复制,但是作为 [=21 的包文档=] 指出:“不应复制包含此包中定义的类型的值。”).
这样做的明显优势是 Counter
的 zero value 是一个有效且现成的计数器(您应该针对您的自定义类型),并且不需要构造函数。