#go #locking #mutex #heap-memory #goroutine
#Вперед #блокировка #мьютекс #куча-память #goroutine
Вопрос:
У меня есть интерфейс под названием Setter. Структура с именем SetterImpl реализует этот интерфейс и имеет 2 установщика, каждый из которых устанавливает 2 интерфейса.
type Setter interface {
A() *AInterface
B() *BInterface
}
type SetterImpl struct {
a *AInterface
b *BInterface
}
func (s *SetterImpl) A(a *AInterface) {
a = a
}
func (s *SetterImpl) B(b *AInterface) {
b = b
}
func returnSetter(a *AInterface, b *BInterface) Setter {
return amp;SetterImpl{a:a, b:b}
}
Установщик, возвращаемый вышеуказанным методом, находится в куче (скажем, в куче) и отправляется на сервер gRPC. Теперь я хочу обновить a и b в SetterImpl таким образом, чтобы сервер gRPC использовал новые значения.
Итак, теперь у меня есть 2 подпрограммы; одна — основная подпрограмма сервера gRPC (скажем, MAIN), другая — разветвленная (скажем, РАЗВЕТВЛЕННАЯ), которая просто предназначена для обновления полей настройки.
Если я использую Мьютекс в FORKED, это, по сути, добавляет забор (например, java). На самом деле он не блокирует никаких переменных (кроме самого себя). Я не хочу, чтобы MAIN мог читать a и b, хранящиеся в SHeap, пока FORKED обновляет их. Потоки API (подпрограммы) на сервере не получают мьютекс чтения перед чтением значений в SHeap. Итак, возможно ли вообще сделать то, чего я пытаюсь достичь? Если да, то как мне этого добиться?
Комментарии:
1. Я не уверен, что здесь означает «SHeap», но блокировка адреса памяти — это не то, что вы должны пытаться. Мьютексы работают только в том случае, если все участники используют блокировку; main должен получить блокировку перед чтением разделяемой памяти.
2. Похоже, у вас сильный опыт работы с Java, и вы, возможно, переносили слишком много этого опыта в свое программирование на Go. Go сильно отличается от Java; хотя синтаксис внешне похож, хороший код Go работает и написан совсем по-другому. Стандартный шаблон интерфейса Java / impl очень неудобен. Программы и потоки не эквивалентны, и ни один из них не эквивалентен разветвлению процесса. Каналы предпочтительнее блокировки, когда это возможно, а когда нет, мьютексы являются механизмом блокировки.
Ответ №1:
Я не думаю, что вы можете заблокировать переменные в Go. Вы можете заблокировать только раздел кода.
m.Lock()
// do stuff
m.Unlock()
Вы создаете проблему для себя из ничего, используя шаблон «интерфейс» против «Impl».
Вы можете упростить свою жизнь, просто используя обычную функцию. Затем вы можете поместить блокировку внутри функции и гарантировать, что она будет защищена.
Поскольку вы создаете интерфейс, вы не можете ничего гарантировать относительно содержимого функции, которая реализует интерфейс.
Ответ №2:
Переменные не могут быть заблокированы. Итак, то, что я пытаюсь сделать, невозможно. Обходной путь, который я сделал, заключался в добавлении a RWMutex
в SetterImpl и выполнении
mux.RLock()
defer mux.RUnlock()
в геттерах a и b в SetterImpl. И когда я хочу установить a и b в РАЗВЕТВЛЕННОМ, я использовал
mux.Lock()
defer mux.Unlock()
Таким образом, если блокировка записи приобретается с помощью FORKED, блокировка чтения не может быть получена в это время. Это возможно, поскольку поле RWLock, созданное в SHeap, используется как глобальная переменная (т. Е. Этот мьютекс никогда не изменяется и передается в РАЗВЕТВЛЕННОМ виде)