Код безопасен, поскольку в нем нет гонки данных.
Однако поведение не определено. Синхронизация с расписанием рутин не выполняется, поэтому может случиться так, что g()
сначала блокирует мьютекс, и как только он освобождается, main()
заканчивается, и ваше приложение может завершить его, а f()
может не завершиться (может даже не запуститься ). Приложение может ничего не печатать, может печатать 2
или может печатать 21
.
. Также может быть, что f()
сначала блокирует, переносит назначения, а затем g()
в main()
распечатает присвоенные новые значения: 21
.
Если вы хотите, чтобы f()
назначил первым, вы можете использовать sync.WaitGroup
, например:
var a, b int
var wg sync.WaitGroup
func f() {
defer wg.Done()
a = 1
b = 2
}
func g() {
print(b)
print(a)
}
func main() {
wg.Add(1)
go f()
wg.Wait()
g()
}
. Это всегда будет печатать 21
, попробуйте на игровой площадке Go .
И запутанный пример, чтобы доказать, что это можно решить также с помощью sync.Mutex
. Это не предназначено для использования, но это также работает:
Блокировка mu
в main()
перед запуском программы. Имейте также g()
блокировку, которая, очевидно, сначала заблокирует. f()
может разблокировать его, как только его работа будет выполнена, давая "зеленый свет" g()
:
var a, b int
var mu sync.Mutex
func f() {
a = 1
b = 2
mu.Unlock()
}
func g() {
mu.Lock()
print(b)
print(a)
mu.Unlock()
}
func main() {
mu.Lock()
go f()
g()
}
Попробуйте это на Go Playground .