Атомное хранилище, за которым следует атомная нагрузка, ведет себя хаотично во всех подпрограммах - PullRequest
0 голосов
/ 02 июня 2019

Я пытаюсь сохранить карту как небезопасную. Указатель и пытаюсь получить ее позже.Ниже приведен фрагмент кода:

package main

import (
    "fmt"
    "sync/atomic"
    "unsafe"
)

type MapHolder struct {
    ptr unsafe.Pointer
}

func (m MapHolder) Set(myMap map[string]int64) {
    atomic.StorePointer(&m.ptr, unsafe.Pointer(&myMap))
    fmt.Printf("The pointer value is: %v\n", atomic.LoadPointer(&m.ptr))
}

func (m MapHolder) Get() map[string]int64 {
    ptr := atomic.LoadPointer(&m.ptr)
    if ptr == nil {
        fmt.Printf("Why is this pointer value nil?")
        return nil
    } else {
        return *(*map[string]int64)(ptr)
    }
}

func main() {
    var m MapHolder
    test := make(map[string]int64)
    test["hello"] = 1
    m.Set(test)
    m.Get()

}

Когда выполняется Set (), он правильно печатает содержимое m.ptr.Однако, когда мы делаем Get (), он возвращает nil.Это выглядит совершенно неожиданным для меня.Я использую Go 1.11.6

Вывод вышеуказанной программы:

The pointer loaded is: 0x40c130
Why is this pointer value nil?

1 Ответ

4 голосов
/ 02 июня 2019

Поскольку у метода Set есть получатель значения, значение получателя и любые изменения значения отбрасываются при возврате метода.Исправьте проблему, используя указатели получателей.

func (m *MapHolder) Set(myMap map[string]int64) { ... }
func (m *MapHolder) Get() map[string]int64 { ... }

В методе Get также необходимо использовать указатель получателя, чтобы предотвратить скачок данных в копии аргумента получателя.

Set метод сохраняет адрес аргумента myMap, а не адрес m в main.Это может или не может быть проблемой в зависимости от того, как приложение использует MapHolder.

...