Go 如何在内部锁定对所有结构字段的并发访问?

Go 如何在内部锁定对所有结构字段的并发访问?,go,Go,如何在内部锁定对所有结构字段的并发访问?假设我有一个结构: type Data struct { ID string Size int //... and more fields } 将在另一个结构中使用的: type Project struct { mu sync.Mutex MetaData Data //... and more fields } 如何修改/获取元数据结构并使用互斥体,同时不向外部包公开其互斥体?我知道我可以使用Ge

如何在内部锁定对所有结构字段的并发访问?假设我有一个结构:

 type Data struct {
    ID string
    Size int
    //... and more fields
 }
将在另一个结构中使用的:

type Project struct {
    mu sync.Mutex
    MetaData Data
    //... and more fields
}

如何修改/获取元数据结构并使用互斥体,同时不向外部包公开其互斥体?我知道我可以使用Get/Set方法,但是如果我需要修改Data struct的一个字段(如果每个字段都有一个具有相同共享互斥体的Get/Set方法,那就不是很好/干净了)该怎么办?您能推荐一种方法/模式,使结构式互斥锁在内部被锁定/解锁吗?

类似的方法如何

type Data struct {
    ID   string
    Size int
    //... and more fields
}

type Project struct {
    mu       sync.Mutex
    metaData Data
    //... and more fields
}

func (p *Project) AccessMetaData(f func(*Data)) {
    p.mu.Lock()
    defer p.mu.Unlock()
    f(&p.metaData)
}

像这样的怎么样

type Data struct {
    ID   string
    Size int
    //... and more fields
}

type Project struct {
    mu       sync.Mutex
    metaData Data
    //... and more fields
}

func (p *Project) AccessMetaData(f func(*Data)) {
    p.mu.Lock()
    defer p.mu.Unlock()
    f(&p.metaData)
}

我对此很好奇,所以我测试了这个,如果父结构被锁定,子结构也被锁定。在当地尝试一下,因为围棋场似乎是确定的

package main

import (
    "fmt"
    "sync"
)

type testGroup struct {
    sync.Mutex
    items map[string]*test
}

type test struct {
    x int
}

var str string = "test"

func increment(t *testGroup, wg *sync.WaitGroup) {
    t.Lock()
    t.items[str].x = t.items[str].x + 1
    t.Unlock()
    wg.Done()
}

func main() {
    var w sync.WaitGroup
    tg := testGroup{}
    tg.items = make(map[string]*test)
    tg.items[str] = &test{}
    for i := 0; i < 1000; i++ {
        w.Add(1)
        go increment(&tg, &w)
    }
    w.Wait()
    fmt.Println("final value of x", tg.items[str].x)
}
主程序包
进口(
“fmt”
“同步”
)
类型testGroup结构{
同步互斥
项目映射[字符串]*测试
}
类型测试结构{
x int
}
var str string=“测试”
func增量(t*testGroup,wg*sync.WaitGroup){
t、 锁()
t、 项目[str].x=t.items[str].x+1
t、 解锁()
wg.Done()
}
func main(){
var w sync.WaitGroup
tg:=testGroup{}
tg.items=make(映射[字符串]*测试)
tg.items[str]=&test{}
对于i:=0;i<1000;i++{
w、 加(1)
go增量(&tg,&w)
}
w、 等等
fmt.Println(“x的最终值”,tg.items[str].x)
}

尝试在
increment()
函数中注释
t.Lock()
t.Unlock()
我对此很好奇,所以我测试了这个,如果父结构被锁定,子结构也会被锁定。在当地尝试一下,因为围棋场似乎是确定的

package main

import (
    "fmt"
    "sync"
)

type testGroup struct {
    sync.Mutex
    items map[string]*test
}

type test struct {
    x int
}

var str string = "test"

func increment(t *testGroup, wg *sync.WaitGroup) {
    t.Lock()
    t.items[str].x = t.items[str].x + 1
    t.Unlock()
    wg.Done()
}

func main() {
    var w sync.WaitGroup
    tg := testGroup{}
    tg.items = make(map[string]*test)
    tg.items[str] = &test{}
    for i := 0; i < 1000; i++ {
        w.Add(1)
        go increment(&tg, &w)
    }
    w.Wait()
    fmt.Println("final value of x", tg.items[str].x)
}
主程序包
进口(
“fmt”
“同步”
)
类型testGroup结构{
同步互斥
项目映射[字符串]*测试
}
类型测试结构{
x int
}
var str string=“测试”
func增量(t*testGroup,wg*sync.WaitGroup){
t、 锁()
t、 项目[str].x=t.items[str].x+1
t、 解锁()
wg.Done()
}
func main(){
var w sync.WaitGroup
tg:=testGroup{}
tg.items=make(映射[字符串]*测试)
tg.items[str]=&test{}
对于i:=0;i<1000;i++{
w、 加(1)
go增量(&tg,&w)
}
w、 等等
fmt.Println(“x的最终值”,tg.items[str].x)
}

请尝试在
increment()
函数中注释出
t.Lock()
t.Unlock()
,小心,这不会锁定访问!这将在获取指针所需的时间内建立一个锁,然后解锁并返回指针,允许调用方对数据进行并发访问(包括写入),而无需任何锁定。是的,函数必须协作,只在函数执行时访问数据,而不保存指针。但是,只要你传递的函数行为正确,它就会执行OP所要求的操作。是否保存指针无关紧要。它可以调用
AccessMetaData()!这将在获取指针所需的时间内建立一个锁,然后解锁并返回指针,允许调用方对数据进行并发访问(包括写入),而无需任何锁定。是的,函数必须协作,只在函数执行时访问数据,而不保存指针。但是,只要你传递的函数行为正确,它就会执行OP所要求的操作。是否保存指针无关紧要。它可以调用
AccessMetaData().Size
并且
Size
的读取将在
AccessMetaData
中的互斥锁之外执行,而
AccessMetaData
不会返回任何内容。