在没有锁的情况下,Golang结构并发读写也运行正常吗? [英] golang struct concurrent read and write without Lock is also running ok?

查看:6
本文介绍了在没有锁的情况下,Golang结构并发读写也运行正常吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

concurrentMap()函数有WARNING: DATA RACE致命错误concurrent map read and map write

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

为什么结构可以数据争用?

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轻量级并发误用映射检测到运行库:

运行库添加了对并发滥用映射的轻量级尽力而为检测。与往常一样,如果一只大猩猩正在向地图写入数据,则不应该有其他大猩猩同时读取或写入地图。如果运行库检测到此情况,它将打印诊断并使程序崩溃。了解有关该问题的更多信息的最佳方法是在race detector下运行程序,这将更可靠地标识竞争并提供更多详细信息。

因此,这是运行库故意造成的崩溃,因为它检测到对映射的不同步访问。这是Go运行时的一个"功能",它会使你的应用程序崩溃,因为你的应用程序中不应该留下数据竞争(以防止未定义的行为)。点击此处了解更多信息:How to recover from concurrent map writes?

这篇关于在没有锁的情况下,Golang结构并发读写也运行正常吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆