Golang нужна блокировка для чтения int - PullRequest
0 голосов
/ 07 марта 2020

В «Языке программирования * 1021», Алан Донован, стр. 264, он использует мьютекс для чтения целого числа.

Я не понимаю, почему, так как целое число помещается в одно слово, поэтому оно не может быть разорванным чтением.

Я, наверное, не прав, но как? Спасибо.

--- Обновление с кодом ---

func Balance() int {
  mu.Lock()
  defer mu.Unlock()
  return balance
}

Затем вниз по странице

func Withdraw(amount int) bool {
  Deposit(-amount)
  if Balance() < 0 {
    Deposit(amount)
    return false // insufficient funds
  }
}

Этот дизайн позволяет балансу стать недействительным, что может быть наблюдаемый читателем, который затем фиксируется в книге с блокировкой в ​​Withdraw() fun c.

Извинения действительно, я думаю, что я потратил впустую время каждого :( Я заставил всех не отвечать на этот вопрос правильно .

Моя теория состоит в том, что если бы переменная balance была проверена (под замком), что есть достаточные средства, прежде чем она мутирует, то блокировка в Balance() fun c не понадобится, но я все еще могу ошибаться, тем более что люди упоминают о переупорядочении, которое является чем-то загадочным.

Ответы [ 3 ]

3 голосов
/ 07 марта 2020

Mutex создан для того, чтобы обеспечить необходимые барьеры памяти и установить sh отношение, случившееся до:

https://golang.org/ref/mem

Гарантия заключается в том, что однажды мьютекс разблокирован, все другие программы, которые обращаются к целому числу, используя тот же мьютекс, увидят значение, которое имеет целое число после разблокировки. Без мьютекса такой гарантии нет; goroutine может увидеть значение int до того, как в него будет записана goroutine писателя.

Хотя модель памяти Go прямо не говорит об этом, атомика также гарантирует то же самое, при условии, что все goroutines предназначены для чтения / записи с использованием атомарные.

2 голосов
/ 07 марта 2020

Если у вас есть одна процедура, вам не нужны специальные средства для чтения и записи переменных.

Если у вас есть несколько процедур, доступ к переменным, доступ к которым осуществляется из нескольких процедур и по крайней мере один из них, запись должна быть синхронизирована.

Цитирование из Модель памяти Go :

В пределах одной процедуры чтения и записи должны вести себя так, как если бы они выполнялись в порядке, указанном программой. Таким образом, компиляторы и процессоры могут переупорядочивать операции чтения и записи, выполняемые в пределах одной процедуры, только когда переупорядочение не изменяет поведение в этой программе, как определено в спецификации языка. Из-за этого переупорядочения порядок выполнения, наблюдаемый одной процедурой, может отличаться от порядка, воспринимаемого другой. Например, если одна процедура выполняет a = 1; b = 2;, другая может наблюдать обновленное значение b перед обновленным значением a.

Хотя Go поощряет другой подход:

Не связываться, разделяя память; вместо этого делитесь памятью, общаясь.

Таким образом, вместо использования блокировок для защиты переменных, вы должны использовать channel для отправки новых значений и результатов вычислений туда, где его необходимо использовать, поэтому чтение общих переменных не потребуется. Каналы безопасны для одновременного использования, гонки данных не могут быть спроектированы.

0 голосов
/ 08 марта 2020

На странице 267 он отвечает на мой вопрос, говоря: «Вы можете задаться вопросом, почему метод Balance() требует взаимного исключения».

Он объясняет это кэшированием процессора, как @Nikita специально упомянул в своем комментарии. Автор также говорит, что нет такой вещи, как добросовестная гонка данных, на которую @JimB ссылался со своей ссылкой в ​​другом комментарии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...