为什么即使锁已锁定,GO仍会因“并发映射写入”而出现恐慌?

时间:2018-10-13 21:21:34

标签: go concurrency mutex goroutine

当尝试将此结构与多个goroutine一起使用时,有时会出现以下错误之一:

fatal error: concurrent map read and map write

concurrent map writes

在阅读this thread之后,我确保在构造函数中返回引用并将引用传递给接收者。

正在使用该代码的完整代码在this github repo

type concurrentStorage struct {
    sync.Mutex
    domain string
    urls map[url.URL]bool
}

func newConcurrentStorage(d string) *concurrentStorage{
    return &concurrentStorage{
        domain: d,
        urls: map[url.URL]bool{},
    }
}

func (c *concurrentStorage) add(u url.URL) (bool) {
    c.Lock()
    defer c.Unlock()
    if _, ok := c.urls[u]; ok{
        return false
    }
    c.urls[u] = true
    return true
}

1 个答案:

答案 0 :(得分:4)

在读取链接到的Github上的代码后,crawl()函数将接受concurrentStorage(不是指针)。

对于调用*urlSet时的每个取消引用(即crawl()),您正在复制concurrentStorage结构(包括sync.Mutex),而映射保留了指针到原来的。这意味着您的互斥锁在每个goroutine共享相同的状态时被隔离。

如果您将crawl()改为接受指针,然后停止取消对concurrentStorage的引用,它将按预期工作。