[운영체제(OS)] 동기화(Synchronization) 와 임계구역 문제(Critical Section Problem) - 1

resilient

·

2022. 1. 9. 15:30

728x90
반응형

0. 동기화 문제란?

 

저번에 공부했듯이 컴퓨터 메모리에는 동시에 여러 프로세스가 존재하는데, 존재하는 프로세스들이 하나의 공유 메모리나 또 다른 프로세스에 접근할 때는 매우 신중해야 합니다.

 

저번에도 한 번 언급했었던 내용인데, 두 개의 프로세스 A, B 가 shared memory를 이용해서 데이터를 주고받는 과정에서 A 가 쓰면 그다음 B가 읽어 가야 하는데 A가 이미 쓴 메모리 영역인지, 이제 써야 할 메모리 영역인지 알 수가 없습니다. 때문에 A가 B에 '나 여기 다 썼다'라고 알려줘야 B가 읽어 갈 수 있죠.

 

프로세스 동기화의 핵심은 여러 프로세스가 공유하는 자원들의 일관성을 유지하는 것입니다. 하나의 공유자원에 여러 프로세스들이 동시에 접근할 때, 프로세스들의 순서를 정해서 동기화가 잘 이루어져 공유 자원들의 일관성을 유지해야 하죠.

 

정리해보면 한 프로세스가 다른 프로세스에 영향을 주거나 받는 프로세스들을 Cooperating process라고 하는데, 요즘에는 거의 대부분의 프로세스들이 Cooperating process입니다. (반대로 독립적인 프로세스들은 Independent process라고 합니다.)

 

따라서 프로세스 간의 동기화가 매우 중요합니다. 프로세스 사이의 동기화를 프로세스 동기화라고 하고, 최근에는 대부분 쓰레드 기준으로 스위칭이 이루어지기 때문에 쓰레드 동기화라고도 많이 부르죠.

 

 

1. 자, 그러면 유명한 은행 계좌 문제 예시를 보겠습니다.

 

A, B 사람이 동시에 한 계좌에서 출금을 하려고 합니다.

현재 잔액이 100만 원 있다고 가정했을 때, 각각 10만 원씩 출금을 시도하면 이 거래를 처리할 프로세스 쓰레드가 생기겠죠?

 

은행계좌에서 출금하는 간단한 코드를 보겠습니다.

 

def withdraw(account, amount):
    balance = get_balance(account)
    balance = balance - amount
    put_balance(account,balance)

 

get_balance , put_balance는 각각 쓰레드를 생성해주고 get_balance는 현재 잔액을 가져오고, put_balance는 변경된 잔액을 갱신해주는 함수입니다.

 

withdraw라는 함수를 수행하면 쓰레드가 동시에 두 개가 생성이 됩니다. 현재 잔액이 100만 원 있다고 가정했으니까 A가 10만 원을 출금하면 3번째 줄에서 balance는 90만 원이 되죠. 여기까지는 문제가 없습니다. 

 

자, 이제 3번째 줄이 실행된 후, timer 인터럽트가 걸렸다고 가정해보겠습니다.

 

인터럽트가 걸리면 인터럽트 핸들러가 수행이 되고, 운영체제가 수행이 되죠. 운영체제가 현재 프로세스를 다 처리한 후, CPU에 다음 프로세스를 올리기 위해서 스케쥴링을 시도하게 됩니다. 대기 중인 프로세스를 보니, A 프로세스는 3 번째 줄까지 완료가 되어있는 거 같습니다. 그래서 다음 B 프로세스로 스케쥴링을 시도했습니다.

 

B 사람이 get_balance로 현재 잔액을 가져오면 얼마가 남았다고 찍힐까요? 원래는 A가 10만 원을 출금했으니 90만원이 나와야할텐데요, A 프로세스에서 put_balance가 실행되기 전에 인터럽트가 발생했으니까 B 한테 계좌 잔액은 100만원이 찍히게 됩니다.

 

그럼 B가 10만원 출금을 시도했으면 80만 원이 남아있어야 하는데 잔액이 90만 원이 남게 되죠. 현실 세계에 이런 일이 있다면 큰일 나겠죠?

 

이렇게 두 개 이상의 concurrent 한 프로세스, 쓰레드들이 공유된 자원에 접근을 할 때, 동기화 해결 과정없이 수행하는 상황을 Race Condition이라고 합니다. 여러개의 프로세스, 쓰레드들이 서로 Race를 한다 이런 의미겠죠?

이제부터는 Race Condition이 발생하지 않게 동기화 처리를 해주는 방법들에 대해서 알아보겠습니다.

 

2. 임계 구역(Critical section) 문제

 

 

임계 구역은 여러 개의 쓰레드가 수행되는 프로그램에서 각 프로세스/쓰레드들이 공유하는 데이터(변수, 파일) 등을 변경하는 코드 영역을 의미합니다.

 

위 그림에서 볼 수 있듯이, 임계 구역이 사용 중일 때는 lock을 걸어주고 critical section에 입장합니다. critical section에서 나갈 때는 lock을 해제해주고 다 썼어!라고 말을 해줘야 하는 것이죠. Critical Section은 동기화에서 중요한 문제 중 하나입니다. 위에서 봤던 은행 계좌 문제에서의 임계 구역을 살펴볼까요?

 

 balance = get_balance(account)

 

임계 구역 문제를 해결하기 위해서는 아래 3가지 조건이 만족되어야 합니다.

 

1. Mutual exclusion (상호 배타) : 오직 하나의 프로세스/쓰레드만 진입 가능하게 합니다. 한 프로세스/쓰레드가 임계 구역에서 수행 중인 상태에서는 다른 프로세스/쓰레드가 절대 수행 중인 임계구역에 접근할 수 없습니다.

2. Progress(진행) : 한 임계구역에 접근하는 프로세스/쓰레드는 다른 프로세스/쓰레드가 쓰고 있지 않으면 사용 가능합니다.

3. Bounded waiting(한계 대기) : 임계 구역으로 진입하기 위해서 대기 중인 프로세스/쓰레드들은 대기하면서 bound를 설정해야 합니다.

 

Mutual exclusion과 Progress는 당연한 내용입니다. 동기화 이슈를 해결하기 위해서는 공유 자원을 쓰고 있을 때는 접근하지 못하도록 막아야 하고, 기다리다가 자리가 나면 바로 자원을 사용할 수 있어야 하죠.

 

Bounded Waiting 조건은 프로세스가 임계 구역으로 들어가기 위해서 요청을 한 후 대기를 할 때 언제까지 대기를 해야할지 bound 를 설정해줘야 무한정 기다리는 경우가 생기지 않기 때문에 필요합니다.

 

3. 정리

 

이번 시간에는 동기화 이슈와 임계구역 문제에 대해서 알아보았습니다.

다음 시간에는 위 3가지 조건을 만족시키면서 Critical Section을 구현하는 방법들을 살펴보겠습니다.

 

[운영체제(OS)] 동기화(Synchronization) 와 임계구역 문제(Critical Section Problem) - 2

0. 들어가면서 저번 시간에는 운영체제에서의 동기화가 무엇인지 살펴보았고, 임계 구역 문제가 무엇인지 알아봤습니다. 이번 시간에는 임계구역을 어떻게 관리하는지, 동기화 문제를 어떻게

resilient-923.tistory.com

 

감사합니다.

 

 

 

반응형