본문 바로가기

CS 과목(CS科目)/운영체제(OS)

동기화(synchronization), 경쟁 조건(race condition), 임계 영역(critical section)

하나의 객체를 두 개의 스레드가 접근할 때 생기는 일

귤박스가 2개 있고, 2개의 스레드에게는 각각 서로 다른 귤 박스를 담당하게 할 것이다. 

badCounter 객체는 2개의 스레드가 공유한다.

만약, 불량인 상태인 각각의 귤박스에 1개씩 있다고 하자. 

그러면 우리가 원하는 state의 값은 2이다.

그러나, 항상 우리가 원하는 값이 높은 확률로 나오지 않는다.

그 이유를 아래에서 살펴보자. 

1. LOAD state to R1 : state값을 cpu 레지스터 R1에 로딩.

2. R1 = R1 + 1 : 레지스터 R1에 +1을 한다.

3. STORE R1 to state  : 레지스토 R1의 값을 메모리에 반환을 한다. 

 

Counter::increament() 메서드의 state++를 어셈블리어로 변환하면 위와 같다.

T1, T2 중 T1이 먼저 CPU(싱글 코어)에서 실행이 된다고 하자.

1~2까지 T1이 실행을 하다가, Time Slice로 인해 Context Switching이 일어났다고 하자.

그럼, R1 = 1이 Heap의 state에 반영이 되지 못한 채 CPU는 T2를 실행을 한다.

T2는 1~3까지의 실행을 모두 마쳐 state=1이 heap 영역에 잘 저장이 돼 있다.

그리고 나서 다시 T1의 3부분이 실행이 되어, R1=1(T1이 종료되면서 Context Switching에 의해 레지스터 R1의 값이 저장

돼 있었다.)이 Heap의 state에 반환이 되서, state는 1이 된다.

자, T1, T2의 실행이 끝나서 State = 1이 된다.

그러나 이건 우리가 원하는 결과값이 아니다.

race condition(경쟁 조건)

여러 프로세스/스레드가 동시에 같은 데이터를 조작(manipulateing)할 때, 타이밍이나 접근 순서에 따라 결과가 다르게 나오는 것.

synchronization(동기화)

여러 프로세스/스레드가 동시에 실행이 돼어도, 공유 데이터의 일관성을 유지시키는 것. 

critical section(임계 영역)

공유 데이터의 일관성을 보장하기 위해 하나의 프로세스/스레드 진입해서 실행 가능한 코드 영역. 

 

Q. 동기화를 하기 위해서, 걍 Context Switching이 일어나지 않게 하면 되는 것 아닌가??

A. 위 방법은 싱글 코어에서만 가능하고, 멀티 코어에서는 해결이 전혀 되지 않는다.
(참고로, 오늘 날의 CPU은 죄다 멀티 코어이다.)

애초에, Context Switching을 발생시키지 않게 하여 해결하는 방법에는 무리가 있다. 

Solution : 위 그림에서 public void increment(){ state++;) 부분을 critical section으로 지정을 해 주면 된다. 

 

임계 영역의 seudo code

 

 

1.mutual exclusion : 한번에 하나의 프로세스/스레드만 임계 영역에서 실행되어야 하낟.

2. progress : 임계 영역에 실행되고 있는 프로세스/스레드가 만약 1개도 없다면,  다른 프로세스/스레드 중 1개가 임계 영역에 들어 가고 싶어할 때, 1개는 실행되게 해야 한다. 

3.bounded waiting : 어떤 프로세스/스레드가 무한정 임계 영역에 못 들어가서는 안 된다라는 것. 

 

동기화 관련 중요 issue

JAVA에서 제공하는 자바 API라고 해서 무조건 Thread-safe한 것이 아니다.

예를 들어, SimpleDateFormat Class는 동기화 문제를 해결해 주지 않으므로, 자바 공식 문서에서는 개발자가 필요하면 반

드시 직접 동기화 issue를 처리하라고 명시돼 있다.

백엔드에서, 더군다나 멀티 쓰레딩 환경에서 개발을 한다면, JAVA에서 제공하는 API라고 하여 동기화 issue가 없다고 맹신

하지 말고, 반드시, 자바 api 문서를 읽고, 해당 class가 동기화 문제를 지원하는지 안 하는지를 확인해야 한다.