Почему GO паникует с «одновременной записью карты», даже если на месте есть блокировки? - PullRequest
0 голосов
/ 14 октября 2018

При попытке использовать эту структуру с несколькими программами иногда я получаю одну из следующих ошибок:

fatal error: concurrent map read and map write

или

concurrent map writes

После прочтения этой ветки я обязательно вернул ссылку в конструкторе и передал ссылку на получатели.

Весь код, в котором он используется, находится в этом репозитории github

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 голосов
/ 14 октября 2018

После прочтения кода на Github, с которым вы связались, функция crawl() принимает concurrentStorage (не указатель).

Для каждой разыменования (то есть: *urlSet) при вызовеcrawl(), вы копируете структуру concurrentStorage (включая sync.Mutex), в то время как карта сохраняет указатель на оригинал.Это означает, что ваши мьютексы изолированы от каждой программы, пока они находятся в одном и том же состоянии.

Если вы измените crawl(), чтобы вместо него принять указатель, и прекратите разыменовывать concurrentStorage, он будет работать какВы намерены.

...