【问题标题】:Why GO panics with 'concurrent map writes' even with locks in place?为什么即使有锁,GO 也会因“并发映射写入”而恐慌?
【发布时间】:2019-03-18 17:49:42
【问题描述】:

当尝试将此结构与多个 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
}

【问题讨论】:

  • 你只是锁定写,你也需要锁定读。
  • 由于您没有包含相应的读取方法,我假设您正在从包中其他位置的 urls 映射中读取。
  • 此时没有执行读取。该结构用于模拟一个集合,基本上是检查该 URL 是否曾被查看过。使用 add() 函数进行检查。现在我添加了一个 size() 函数,该函数执行锁定以获取地图的大小。

标签: go concurrency mutex goroutine


【解决方案1】:

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

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

如果您将crawl() 改为接受指针,并停止取消引用concurrentStorage,它将按您的意愿工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-26
    • 1970-01-01
    • 1970-01-01
    • 2021-07-05
    • 1970-01-01
    • 1970-01-01
    • 2019-05-10
    • 1970-01-01
    相关资源
    最近更新 更多