package main
import (
"fmt"
"sync"
"time"
)
type Account struct {
Balance int
}
func main() {
var wg sync.WaitGroup
account := &Account{0}
wg.Add(10)
for i := 0; i < 10; i++ {
go func() {
for {
DepositAndWithdraw(account)
}
wg.Done()
}()
}
wg.Wait()
}
func DepositAndWithdraw(account *Account) {
if account.Balance < 0 {
panic(fmt.Sprintf("Balance should not be negative value: %d", account.Balance))
}
account.Balance += 1000
time.Sleep(time.Millisecond)
account.Balance -= 1000
}
예제 그대로 따라친건디..
패닉이 떠야하는디..
아마 원래 의도는 고루틴을 사용하게 되면서, account.balance에 1000이 더해지거나 빼지는게 서로 다른 고루틴들에 의해 중첩된다는 걸 보여주려고 했던 것 같네요. 하지만 1000을 먼저 더하고 나중에 빼주는 구조기 때문에 0 미만으로 내려갈 일은 없어서 panic을 할 일이 없네요.
account 초기값을 1000으로 하고, DepositAndWithdraw 함수에서 account.balance+=랑 -= 순서 바꿔주면 panic 일어날 거에요. 의도상 예제로는 이게 더 적절할 것 같네요
감사합니다 ㅠㅠ
이거 main 함수에서 for 루프 i 값을 500정도로 조정하고 기다리시면, panic 발생하는 거 보실 수 있습니다.
DepositAndWithdraw가 500개 실행되다 보니 account balance값이 +1000되기 이전에, 2개 이상의 고루틴이 같은 값을 읽고 -1000하게 되어 0미만 되는 시점이 발생합니다.
당연한 얘기지만, wg.Add(n)도 수정하셔야 합니다!~
원리 관해서는 맞는 말씀이시긴 한데, 구조상 -1000이 중첩되기 전에 +1000의 중첩이 먼저 시행되기 때문에 결국 0 미만으론 내려가지 않습니다. for문 안에 println넣어봐서 확인해보면 알 수 있고요. 위 예제처럼 고루틴 개수나 for문 반복 횟수 10정도로만 해도 0-3000에서 왔다갔다하면서 중첩되는거 확인할 수 있습니다.
아하, 피드백 감사합니다~
개인적으로 테스트 할 때 0미만으로 내려가는 상황이 나와서 패닉이 발생했는데, 다시 39.7님 말씀대로 값을 찍어보니 0미만으로 내려가는 일이 없네요. 뭔가 제가 잘못 돌려보고 이해한 것 같습니다! 다시 한번 피드백 감사합니다 :)
제가 잘못 이해했었네요...위의 예제엔 잘못된 게 없고, 218.152님 말이 맞습니다. race condition에 대해 제대로 이해하지 못한 채 함부로 말을 했네요. 나중에 헷갈리는 사람 없도록 정리해서 올리도록 하겠습니다
오, 정리해서 올려주면 감사하겠습니다 :)