Go определение типа уязвимости и предложения по его предотвращению
Имеется следующий код:
func race(){
wait := make(chan struct())
n := 0
go func () {
n++
}()
n++
fmt.Println(n)
}
И следующее ТЗ:
К какой уязвимости приведет реализация этого функционала? Опишите уязвимость и предложите свои варианты предотвращения.
Всё что я могу сказать по этому поводу, так это то что "n" по итогу будет 1, а не 2, а так же может возникнуть ошибка из-за того, что "wait" не используется...
Я вижу данный код следующим образом для корректной отработки:
package main
import "fmt"
func main() {
wait := make(chan int)
n := 0
go func() {
wait <- 1
}()
n += <-wait
n++
fmt.Println(n)
}
Но я не думаю, что такое банальное решение является решением. У кого какие идеи и предположения?
Ответы (1 шт):
Достаточно обратить внимание на название функции :)
Этот код создает ситуацию гонки (race condition).
В данном случае, одновременно выполняются две операции: горутина (go func()) увеличивает n на 1, и основной поток также увеличивает n на 1.
Так как порядок выполнения этих операций не определен, n может быть либо 1, либо 2 в момент вывода, в зависимости от того, какой поток выполнился первым. Это делает поведение программы непредсказуемым и потенциально ошибочным.
Чтобы предотвратить эту уязвимость, можно использовать [механизмы синхронизации, такие как мьютексы (mutexes) или каналы (channels), чтобы гарантировать, что только один поток может изменять переменную в данный момент времени.
Пример с использованием мьютекса:
func race() {
var mu sync.Mutex
n := 0
go func() {
mu.Lock()
n++
mu.Unlock()
}()
mu.Lock()
n++
mu.Unlock()
fmt.Println(n)
}
В этом примере
mu.Lock()блокирует доступ к переменнойnдля других потоков, пока текущий поток не вызоветmu.Unlock(), после чего доступ кnстановится возможным для других потоков.
Пример с использованием канала:
func race() {
n := 0
done := make(chan bool)
go func() {
n++
done <- true
}()
n++
<-done
fmt.Println(n)
}
Здесь канал
doneиспользуется для синхронизации потоков. Горутина отправляет значение в каналdoneпосле увеличенияn, и основной поток ждет это значение перед выводомn, что обеспечивает последовательное увеличениеn.