go - 取消引用指针的类型断言是 Go 中的内存写入吗?

标签 go synchronization race-condition

go 竞争检测器以一种对我来说毫无意义的方式提示我的代码,但我猜竞争检测器的作者比我更了解这一点。

我有这个关闭:

func(f *datastore.F) bool {
    a, ok := (*f).(*datastore.T)
    ...
}

我作为参数传递给这个函数:

func GetFunc(f func(fid *datastore.F) bool) (*datastore.F, bool) {
    kvs.lock.RLock()
    defer kvs.lock.RUnlock()

    for _, v := range kvs.fs {
        if f(v) {
            return v, true
        }
    }
    return nil, false
}

这是另一个 goroutine 的相关部分:

for read := range [chan of datastore.F] {
    s.lock.Lock()
    s.fs[read.Fi()] = &read
    s.lock.Unlock()
}

kvs 是这种类型的一个实例:

type kvstore struct {
    lock  sync.RWMutex
    fs map[datastore.Fi]*datastore.F
}

datastore.F 是一个接口(interface),*datastore.T 实现该接口(interface)。

竞争检测器提示闭包和另一个 goroutine 存在数据竞争。另一个 goroutine 写入,闭包读取。我不明白的是,考虑到 sync.RWMutex 就位,这会如何发生冲突。

最佳答案

解引用指针的类型断言不会写入 Go 中的变量。

这段代码

for read := range [chan of datastore.F] {
   s.lock.Lock()
   s.fs[read.Fi()] = &read
   s.lock.Unlock()
}

将映射值设置为局部变量read的地址。变量 read 的作用域位于 for 循环 block 之外,并且在循环的每次迭代中都会被修改。所有映射值都包含相同的指针,这可能不是您想要的。

闭包通过取消引用映射中的指针来读取变量read。竞争检测器会提示,因为读取器(闭包)和写入器(for 循环)之间没有同步。

要解决此问题,请在循环内声明一个新变量:

for read := range [chan of datastore.F] {
   read := read  // <-- Add this line
   s.lock.Lock()
   s.fs[read.Fi()] = &read
   s.lock.Unlock()
}

通过此更改,每个映射值都指向设置一次的唯一变量。

Go 中很少使用接口(interface)指针。解决此问题的首选方法是将 *datastore.F 类型的所有使用更改为 datastore.F。此更改消除了跨 goroutine 边界对变量 read 的引用,并消除了不必要的间接级别。

关于go - 取消引用指针的类型断言是 Go 中的内存写入吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31395316/

相关文章:

go - 防止修改结构数据成员的惯用方法

c++ - 运行 regsvr32.exe 时,带有线程句柄的 WaitForSingleObject 卡住

mysql - 为什么当存在唯一索引时会出现死锁错误

http - 在超时处理程序中进入竞争条件

go - 如何在递归函数中设置mutex和sync.waitgroup?

go - 如何在golang中查找sshd服务状态

go - 在多行 Fyne Entry 小部件中捕获 Enter (更一般地,调用 "parent classes")

windows - 仅在一个处理器上运行的进程是否可以在其他处理器上运行线程?

android - 如何将 Android 数据库与在线 SQL Server 同步?

java - JFreeChart addBin 具有竞争条件?