草庐IT

dictionary - golang struct concurrent read and write without Lock 也运行ok?

coder 2023-06-28 原文

concurrentMap() 函数有WARNING: DATA RACE, 和fatal error: concurrent map read and map write

concurrentStruct() 有警告:数据竞争,但运行正常

为什么struct可以DATA RACE?

package main

import (
    "sync"
)

func main() {
    // concurrentMap()
    concurrentStruct()
    // concurrentStructWithMuLock()
}

type Metadata struct {
    mu  sync.RWMutex // ?
    key bool
}

// concurrentStruct 并发操作结构体
// concurrent read and write the struct
// go run -race  main.go   有 WARNING: DATA RACE,但是可以运行
// go run -race  main.go   It have WARNING: DATA RACE, But running ok
func concurrentStruct() {
    m := new(Metadata)

    for i := 0; i < 100000; i++ {
        go func(metadata *Metadata) {
            for {
                readValue := metadata.key
                if readValue {
                    metadata.key = false
                }
            }
        }(m)

        go func(metadata *Metadata) {
            for {
                metadata.key = true
            }
        }(m)
    }

    select {}
}

// concurrentStructWithMuLock  并发操作(使用了读写锁)结构体
// concurrent read and write the struct with RWMutex
// go run -race  main.go   没有 WARNING: DATA RACE
// go run -race  main.go   Don't have WARNING: DATA RACE, and running ok
func concurrentStructWithMuLock() {
    m := new(Metadata)

    go func(metadata *Metadata) {
        for {
            metadata.mu.Lock()
            readValue := metadata.key
            if readValue {
                metadata.key = false
            }
            metadata.mu.Unlock()
        }
    }(m)

    go func(metadata *Metadata) {
        for {
            metadata.mu.Lock()
            metadata.key = true
            metadata.mu.Unlock()
        }
    }(m)

    select {}
}

// concurrentMap 并发读写 Map
// concurrent read and write the map
// go run -race  main.go   有 WARNING: DATA RACE,不可运行,fatal error: concurrent map read and map write
// go run -race  main.go  Have WARNING: DATA RACE, And fatal error: concurrent map read and map write
func concurrentMap() {
    m := make(map[int]int)
    go func() {
        for {
            _ = m[1]
        }
    }()
    go func() {
        for {
            m[2] = 2
        }
    }()
    select {}
}

最佳答案

从多个 goroutine 中对任何变量进行不同步的并发访问,其中至少有一个是写入是未定义的行为。不要试图在未定义的行为中寻找逻辑,只需使用适当的同步即可。未定义意味着它可能“正确”运行,也可能“错误”运行(给出不正确的结果),或者它可能崩溃或其他任何事情。这就是未定义的意思。在这里阅读更多相关信息:Is it safe to read a function pointer concurrently without a lock?

您的 concurrentStructWithMuLock() 实际上没有数据竞争,因为您正在使用互斥锁来正确同步对结构的访问。

对于 concurrentMap(),这是另一个问题。 Go 1.6 added轻量级并发误用映射检测到运行时:

The runtime has added lightweight, best-effort detection of concurrent misuse of maps. As always, if one goroutine is writing to a map, no other goroutine should be reading or writing the map concurrently. If the runtime detects this condition, it prints a diagnosis and crashes the program. The best way to find out more about the problem is to run the program under the race detector, which will more reliably identify the race and give more detail.

所以这是运行时故意的崩溃,因为它检测到对 map 的不同步访问。这是 Go 运行时的一个“功能”,它会使您的应用程序崩溃,因为您的应用程序中不应留下任何数据竞争(以防止未定义的行为)。在这里阅读更多相关信息:How to recover from concurrent map writes?

关于dictionary - golang struct concurrent read and write without Lock 也运行ok?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51301328/

有关dictionary - golang struct concurrent read and write without Lock 也运行ok?的更多相关文章

随机推荐