Наведите указатель на локальную переменную, созданную в функции

# #multithreading #go #pointers #slice #goroutine

Вопрос:

Вот код:

 var timePointer *[]time.Time

func UpdateHolidayList() error {
    //updating logic: pulling list of holidays from API
    
    holidaySlice := make([]time.Time, 0)

    //appending some holidays of type time.Time to holidaySlice
    //now holidaySlice contains a few time.Time values

    timePointer = amp;holidaySlice

    return nil
}

func main() {

//run UpdateHoliday every 7 days
    go func() {
        for {
            UpdateHoliday()
            time.Sleep(7 * 3600 * time.Hour)
        }
    }()

}
 

У меня есть 4 вопроса:

  1. holidaySlice является ли локальная переменная, безопасно ли указывать на нее (глобальный) указатель?
  2. Безопасен ли весь этот многопоточный код?
  3. После указания timePointer на holidaySlice , могу ли я получить доступ к значениям через timePointer
  4. (Если ответ на 3. «да») Список праздников постоянно меняется, поэтому holidaySlice каждое обновление будет отличаться. Изменятся ли тогда значения, доступные через timePointer , соответствующим образом?

Ответ №1:

holidaySlice является локальной переменной, выделенной в куче. Любая переменная, указывающая на одно и то же расположение кучи, может получить доступ к структуре данных в этом месте. Является ли он безопасным или нет, зависит от того, как вы получите к нему доступ. Даже если holidaySlice он явно не был выделен в куче, как только вы укажете на него глобальную переменную, компилятор Go обнаружит, что она «ускользает», поэтому он выделит ее в куче.

Код не является потокобезопасным. Вы изменяете общую переменную (глобальную переменную) без какой-либо явной синхронизации, поэтому нет никакой гарантии, когда или если другие городские службы увидят обновления этой переменной.

Если вы обновляете содержимое timePointer массива без явной синхронизации, нет никакой гарантии, когда или если другие городские сети увидят эти обновления. Вы должны использовать примитивы синхронизации, например sync/Mutex , для ограничения доступа на чтение/запись к структурам данных, которые могут быть обновлены/прочитаны несколькими линиями.

Ответ №2:

  1. До тех пор, пока ваш основной не закончится timePointer , у вас будет доступ к указателю, который holidaySlice создает — поскольку его куча выделена, компилятор обнаружит его побег и не освободит память.
  2. Нет, абсолютно нет. Посмотрите на пакет синхронизации
  3. Да, ты можешь. Просто не забудьте повторить, используя *timePointer вместо timePointer
  4. Это изменится — но не соответствующим образом. Поскольку вы не выполнили никакой синхронизации — у вас нет определенного способа узнать, какие данные хранятся в срезе, на который указывает, timePointer когда они считываются.