하나의 객체에 두개의 스레드가 접근할 때 무슨일이 생길까?..
상한 귤을 골라내는 예제
귤 2box를 box당 한개의 스레드가 담당해서 2개의 스레드 사용
두스레드가 공유하는 변수 badCounter
메모리안에 힙 영역안에 두스레드에서 모두 접근 가능한 badCounter라는 객체가 존재할 것 state = 0
CPU 싱글코어로 가정 쓰레드 T1 T2가 1개의 코어에서 동작 하기 때문에 멀티 태스킹으로 동작하며 중간 중간 CS 일어나서 CPU에서 T1과 T2에서 번갈아가며 실행할 것
먼저 정답을 정해두고 가정을 하고 시작해 보자
A box에는 상한귤이 2개 B box에는 상한귤이 5개 있다고 가정할경우 badCounter의 state = 7이 될 것이라고 생각할 수 있다.
과연 항상 그럴까?
두 스레드가 같이 접근해서 사용할수 있는 badCounter의 increment() 메소드에서 state++가 실제로 cpu레벨에서 어떻게 동작하는지 생각해보자
state++라는 언어를 컴퓨터상에서 CPU가 이해할 수 있는 언어( 명령어 )로 바꿔야함
- LOAD STATE to R1
- R1 = R1 +1
- STORE R1 to STATE
=> 메모리에 state변수에 있는 값을 R1이라는 CPU안에 포함된 레지스터로 로드한 후 그 레지스터에 있는 값에 1을 더하고 레지스터에 저장하고 최종적으로 다시 그 레지스터에 있는 값을 다시 메모리에 있는 변수state에 저장해라 라는 3줄짜리 명령어
이제 편의상 1 - 3의 각 과정을 1번 2번 3번이라고 정의하고 진행 해보자
- 먼저 쓰레드 t1이 1번 과정을 실행
- 2번을 실행하면서 R1값에 1이 저장하고 CS발생
- 쓰레드 t2 시작
- 다시 t2가 1번 과정 실행 이떄는 아직 state=0
- 2번을 실행하면서 R1에 1이 저장
- 3번을 시작하면서 State에 1이 저장 state=1 그리고 CS발생
- 다시 t1으로 돌아가서 시작
- R1 1값 로딩후 3번 실행 state=1에서 R1값에 1을 덮어씌움 state=1
서로 한번씩 호출해서 state=2를 기대했으나 state1이 나왔음!!
=> t2에서 state값을 가져올때 t1에서 작업한 내용이 메모리에 다 써지지 않은 것을 가져와서 문제가 생김 ( t1에서 반영되지 않은 메모리값 t2에서 사용 )
언제 CS가 일어나느냐에 따라 State의 결과값이 달라지는 현상 발생
여러 프로세스/스레드가 동시에 같은 데이터를 조작할 때 타이밍이나 접근 순서에 따라 결과가 달라질 수 있는 상황
여러 프로세스/스레드를 동시에 실행해도 공유 데이터의 일관성을 유지하는 것
위 귤예시에서 어떻게 동기화 시킬까?
1차원적으로 생각하면 state++가 CPU단계에서( 1~3번과정 ) 이루어질때는 CS가 일어나지 않도록 하면 된다고 생각 할 수 있음
=> 싱글 코어에서만 가능하기때문에 무리수가 있음
그래서 해결방안은
increment()를 실행할때 한번에 한 스레드만 실행할 수 있게 하는 방법
=> 다른 스레드가 이 메서드를 호출하고 있을경우 그 작업이 끝날때까지 다른 스레드가 호출이 끝날때 까지 기다리는 방법
공유 데이터의 일관성을 보장하기 위해 하나의 프로세스/스레드만 진입해서 실행 가능한 영역
do{
entry section
critical section
exit section
remainder section
}while (true)
critical section 안으로 진입하기 위해서는 entry section에서 조건이 되는지를 확인해야함. 그리고 들어와서 작업을 마치고 critical section에서 나가기 위해서도 마찬가지로 exit section의 조건을 만족해야함