Какую гарантию синхронизации даёт освобождение sync.Mutex для следующей успешной блокировки этого мьютекса другой горутиной?
Освобождение sync.Mutex синхронизируется с последующей успешной блокировкой того же мьютекса. Поэтому записи, выполненные горутиной до Unlock, становятся видимыми горутине после её успешного Lock.
Эта гарантия действует только для доступа, защищённого тем же мьютексом. Сам по себе вызов Unlock не делает безопасными параллельные чтения или записи, выполняемые без блокировки.
При совместном доступе горутин к памяти требуется решить две разные задачи: не допустить одновременного изменения данных и обеспечить предсказуемую видимость изменений между процессорами и потоками выполнения.
Мьютекс решает обе задачи для критической секции: только владелец блокировки работает с защищёнными данными, а передача блокировки устанавливает порядок между операциями разных горутин.
Рассмотрим общий объект, который одна горутина изменяет, а другая читает. Если запись и чтение выполняются без общего механизма синхронизации, возникает гонка данных: результат зависит от межпоточного порядка, а программа нарушает требования модели памяти Go.
Даже если на практике читатель часто видит новое значение, полагаться на это нельзя. Нужна пара операций над одним мьютексом: запись выполняется до Unlock, а чтение — после успешного Lock.
Для одного экземпляра Mutex действует отношение синхронизации: вызов Unlock упорядочен перед последующим успешным Lock того же мьютекса. Следовательно, операции записи до освобождения блокировки становятся наблюдаемыми после получения этой блокировки.
Горутина-читатель может запуститься раньше записи, но она не сможет пройти свой Lock, пока первая горутина не выполнит Unlock. После получения мьютекса она должна увидеть значение 42, поскольку запись была выполнена до освобождения блокировки.
Важно, что мьютекс защищает не переменную автоматически, а дисциплину доступа к ней. Все чтения и записи общего состояния должны использовать согласованный мьютекс; если хотя бы один доступ выполняется без него, защита неполна.
Mutex не гарантирует справедливый порядок обслуживания и не заменяет ожидание завершения горутины. Он также не сообщает, когда состояние достигло нужного значения: для этого может потребоваться канал, sync.Cond, WaitGroup или другой механизм.
Блокировку следует освобождать на всех путях выхода, обычно через defer mu.Unlock() сразу после успешного Lock. Нельзя копировать уже использованный Mutex, поскольку копия не является тем же объектом синхронизации.
В кэше несколько горутин обновляют карту, а другие одновременно читают её. Вариант с отсутствием блокировки имеет минимальные накладные расходы в спокойном тесте, но приводит к гонкам и может завершиться аварийно при конкурентной работе с обычной картой.
sync.RWMutex позволяет параллельным читателям работать одновременно, но усложняет код и не обязательно ускоряет систему: при частых записях, коротких критических секциях или высокой конкуренции накладные расходы могут превысить выигрыш. Передача каждого запроса через канал сериализует доступ и может упростить владение состоянием, но добавляет отдельную горутину-владелец и задержки обмена.
Если кэш небольшой, критические секции короткие, а чтения и записи перемешаны, обычно выбирают обычный sync.Mutex. Он даёт понятную гарантию видимости, минимизирует сложность и после измерений может быть заменён на другой механизм при наличии доказанной потребности.
Нет. Чтение без той же синхронизации остаётся конкурентным доступом к общей памяти. Если запись может происходить одновременно с чтением, возникает гонка данных; кроме того, нет гарантии, что читатель увидит актуальное значение. Защищать нужно все конфликтующие доступы либо использовать другой корректный механизм, например атомарные операции для подходящего типа данных.
Unlock немедленную передачу управления конкретной ожидающей горутине?Нет. Он устанавливает отношение синхронизации с последующей успешной блокировкой, но не обещает, какая именно горутина получит мьютекс первой и когда это произойдёт. Поэтому мьютекс нельзя использовать как механизм очереди или точного планирования.
Mutex запуск горутины с её последующими действиями?Нет. Сам факт запуска горутины не означает, что она уже выполнила код, а Lock не является ожиданием завершения другой горутины. Синхронизация возникает только между соответствующими операциями над мьютексом: изменения до Unlock могут быть переданы горутине, которая затем успешно выполнила Lock. Для ожидания завершения нужен отдельный механизм, например WaitGroup или канал.