我要我觉得! 我觉得对了,但是被结果打了脸

wang-laoban · 2019-10-11 14:16:45 · 1289 次点击 · 预计阅读时间 2 分钟 · 大约8小时之前 开始浏览    
这是一个创建于 2019-10-11 14:16:45 的文章,其中的信息可能已经有所发展或是发生改变。

func main() {
    f4()
}
func f4() {
    m := make(map[string]int)
    var lock sync.RWMutex

    go func(m map[string]int, l sync.RWMutex) {
        for {
            time.Sleep(time.Second * 1)
            l.RLock()
            fmt.Println("token now is : ", m["a"])
            l.RUnlock()
        }   
    }(m, lock)

    for {
        time.Sleep(time.Nanosecond * 1)
        lock.Lock()
        m["a"] = rand.Int()
        lock.Unlock()
    }   
}

讲道理没啥问题呀,怎么还会报读写冲突呢?能解此迷的绝对是牛人。

token now is : 1013340838

token now is : 1876733110

token now is : 166916850

fatal error: concurrent map read and map write

goroutine 5 [running]: runtime.throw(0x80e8a1a, 0x21) /usr/local/go/src/runtime/panic.go:608 +0x6a fp=0x842c768 sp=0x842c754 pc=0x806b8fa runtime.mapaccess1_faststr(0x80d1960, 0x8448120, 0x80e408f, 0x1, 0x0) /usr/local/go/src/runtime/map_faststr.go:21 +0x34a fp=0x842c7a0 sp=0x842c768 pc=0x8054e4a main.f4.func1(0x8448120, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0) /root/go/test/tamp/main.go:31 +0x80 fp=0x842c7d0 sp=0x842c7a0 pc=0x80bee70 runtime.goexit() /usr/local/go/src/runtime/asm_386.s:1324 +0x1 fp=0x842c7d4 sp=0x842c7d0 pc=0x8091201 created by main.f4 /root/go/test/tamp/main.go:27 +0x62

goroutine 1 [runnable]: time.Sleep(0x1, 0x0) /usr/local/go/src/runtime/time.go:100 +0x110 main.f4() /root/go/test/tamp/main.go:36 +0x76 main.main() /root/go/test/tamp/main.go:21 +0x17 exit status 2


有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1289 次点击  
加入收藏 微博
4 回复  |  直到 2019-10-11 17:45:39
gojuukaze
gojuukaze · #1 · 6年之前

你的lockl不是同一个锁,mm是同一个。
两种改法:

1:

go func() {
        for {
            time.Sleep(time.Second * 1)
            lock.RLock()
            fmt.Println("token now is : ", m["a"])
            lock.RUnlock()
        }
    }()

2:

go func(m map[string]int, l *sync.RWMutex) {
        for {
            time.Sleep(time.Second * 1)
            l.RLock()
            fmt.Println("token now is : ", m["a"])
            l.RUnlock()
        }
    }(m, &lock)
jan-bar
jan-bar · #2 · 6年之前

这就是典型的,值传递和指针传递的坑。

guoapeng
guoapeng · #3 · 6年之前

不是同一个锁,这就是传值和传引用的差别("pass by value" vs "pass by reference") 将两个锁的地址打印出来比较你会发现,不指向同一个对象

func f4() {
    m := make(map[string]int)
    var lock sync.RWMutex

    go func(m map[string]int, l sync.RWMutex) {
        for {
            time.Sleep(time.Second * 1)
            fmt.Printf("lock B is %p :\n ", &l)
            l.RLock()
            fmt.Println("token now is : ", m["a"])
            l.RUnlock()
        }
    }(m, lock)

    for {
        time.Sleep(time.Second * 1)
        fmt.Printf("lock A is %p :\n ", &lock)
        lock.Lock()
        m["a"] = rand.Int()
        lock.Unlock()
    }
}

output

lock A is 0xc0000123c0 :
 lock B is 0xc000090000 :
 token now is :  605394647632969758
wang-laoban
wang-laoban · #4 · 6年之前

第一次发文章提问,胆战心惊。。没想到这么快就有回复,感谢各位码的字 :beer: :beer: :beer: :beer: :beer:

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传