我在Essential Go中看到,在结构体中使用互斥体并不是太简单。引用Mutex 陷阱页面:
\n\n\nDon\xe2\x80\x99t 复制互斥体
\n变量的副本
\nsync.Mutex
以与原始互斥体相同的状态开始,但它不是相同的互斥体。\n
sync.Mutex
通过将eg传递给另一个函数或将其嵌入到结构中并制作该结构的副本来复制eg几乎总是错误的。如果您想共享互斥变量,请将其作为指针传递\n
\n*sync.Mutex
。
我不太确定我是否完全理解所写的内容。我看了这里,但仍然不太清楚。
\n以 Essential Go 的Set为例,我应该像这样使用互斥体:
\ntype StringSet struct {\n m map[string]struct{}\n mu sync.RWMutex\n}\n
Run Code Online (Sandbox Code Playgroud)\n或者像这样?
\ntype StringSet struct {\n m map[string]struct{}\n mu *sync.RWMutex\n}\n
Run Code Online (Sandbox Code Playgroud)\n我在示例中尝试了两者的 Delete() 函数,它们都在Playground中工作。
\n// Delete removes a string from the set\nfunc (s *StringSet) Delete(str string) {\n s.mu.Lock()\n defer s.mu.Unlock()\n delete(s.m, str)\n}\n
Run Code Online (Sandbox Code Playgroud)\n显然会有多个“Set”实例,因此每个实例都应该有自己的互斥锁。在这种情况下,是使用互斥锁还是指向互斥锁的指针更好?
\n使用第一种方法(一个普通的互斥体,而不是指向互斥体的指针),并传递 a *StringSet
(指向结构的指针),而不是普通的StringSet
.
在您在游乐场(该版本)中共享的代码中:
.Add()
,.Exists()
并且.Strings()
应该获取锁,如果您操作普通结构,则“不要复制互斥体”陷阱将适用StringSet
:
var setA StringSet
setA.Add("foo")
setA.Add("bar")
func buggyFunction(s StringSet) {
...
}
// the gotcha would occur here :
var setB = setA
// or here :
buggyFunction(setA)
Run Code Online (Sandbox Code Playgroud)
在上述两种情况下:您将创建完整结构的副本
setB
例如,so将操作与 相同的底层map[string]struct{}
映射setA
,但互斥锁不会被共享:调用setA.m.Lock()
不会阻止修改来自 的映射setB
。