본문 바로가기
컴퓨터 공학/운영체제

Chapter 6. 동기화 도구들 - 1부

by 조엘 2020. 10. 20.

안녕하세요 조엘입니다! 운영체제 6단원에 대해 공부해 보았습니다. 내용이 많아서 몇 부작이 될지 모르겠네용ㅜㅜ

Abraham Silberschatz의 Operating System Concepts 10th edition과 학부 수업을 듣고 정리한 내용입니다. 오개념이 있다면 알려주세요~~

 

 

우선 본격적인 내용 공부에 앞서 최호성 선생님의 강의를 잠깐 듣고 가자. 운영체제 공부하면서 계속 나오는 용어들에 대해 비유적으로 이해할 수 있게 알려주시는데, 정리하고 가면 좋을 것 같다!

 

<용어 정리>

 - 동시성: 여러 일을 여러 사람이 각자 동시에 하는 것

 - 병렬성: 같은 일을 여러 사람이 동시에 하는 것

 - 원자성: 감히 쪼개어 나눌 수 없는 연속된 일

 - 의존성: 행위나 존립에 대해 의존 하는 것

 

원자성과 동기화를 화장실에서 볼일 볼 때 문을 걸어 잠그는 것으로 표현해 주신다. 

화장실에서 볼 일 보러 들어가서 일을 처리하고 나올 때 까지는 혼자 화장실을 사용할 수 있도록 보장해야 한다. 그렇게 하기 위해 화장실에서 문을 잠가서 볼 일을 보지 않느냐?

여기서 화장실에 들어가 ~ 일을 처리하고 나옴이 원자성, 문을 잠가서 볼 일을 보는게 동기화!

기본 용어를 이해했으니, OS 6단원 포스팅 시작해본다. 

 

<프로세스 동기화의 필요성?>

우리의 시스템은 병행/병렬적으로 실행되는 수백, 수천 개의 프로세스로 이루어져 있다.

이 중 협력적 프로세스는 시스템 내에서 실행 중인 다른 프로세스의 실행에 영향을 주거나 영향을 받는 프로세스로, 사용자 데이터를 공유할 수도 있다. 

여기서 문제는, 공유되는 데이터에 대해 협력적 프로세스간의 동시성이나 접근 순서가 제어되지 않는다면?

프로세스의 실행 이후에 데이터의 값이 정확하다고 보장할 수가 없다! 

따라서, 프로세스 동기화 작업은 위에서 설명한 공유 데이터에 다 같이 동시에 접근하는 Race Condition을 피하고자, 공유 데이터에 대한 액세스를 제어하는 도구를 사용하게 된다. 

하지만, 이 도구를 또 잘못 사용하면, 시스템 성능이 저하되는 "Deadlock" 상태에 빠질 수 있으니 조심해서 사용하자!

 

<유한 버퍼 모델로 알아보는 데이터 일관성 문제>

프로세스 간 통신을 위한 공유 메모리를 구현하기 위해 버퍼의 개념을 3단원에서 도입했었다.

이 중 길이가 정해져 있는 유한 버퍼를 사용하게 되면, 공유 데이터를 (버퍼의 크기-1) 개 만큼만 사용할 수 있었다.

이는 자료구조가 아래 그림처럼 버퍼의 첫번째 index, 그 다음 free해줄 index만 기록하고 있어, 두 개의 값이 같아지는 경우 꽉 찬 건지, 텅 빈 건지 구분이 안 돼서 그랬던 것이다. 

유한 버퍼를 사용한다면 (버퍼 사이즈-1)개만 사용한다

유한 버퍼의 이러한 특성을 해결하고자, count라는 변수를 자료구조에 추가해서 총 몇개의 공유 데이터가 버퍼 안에 들어가 있는 지를 체크하자. 이를 통해 우리는 공유 데이터를 버퍼 사이즈 만큼 집어 넣을 수 있다. 

Count 변수를 추가한 후, Producer-Consumer 모델의 논리 구조

코드만 딱 봤을 때는 문제가 없어 보입니다만, 실행해 보면 문제가 발생한다. 바로 count라는 변수를 producer와 consumer 둘 다 에서 접근하기 때문이다!! count의 증감 연산자는 레지스터를 거쳐 처리가 된다 (아래 그림 참조).

만약 producer가 처리 중인 순간에 consumer로 context-switching이 일어나서 count연산을 진행한다? 그런 다음에 producer로의 context-switching이 일어나서 마저 count연산을 진행한다? 말이 참 복잡한데, 결과는 더 복잡하다. 

Count 변수에 대한 경쟁 상태

이처럼 예상치 못한 결과를 불러 일으키는 것은 count에 대한 race condition이 발생했기 때문이다. 위에서 살펴본 개념 "원자성"이 보장되지 않았기 때문이다! 

 

<Critical Section> 

위에서 살펴 본 것 처럼, count라는 변수가 한 프로세스에서 조작되고 있을 때, 또 다른 프로세스가 count 변수를 조작하려 든다? 그러면 알맞은 결과가 Race condition으로 인해 보장이 되지 않는다. 

이와 같이 적어도 하나 이상의 다른 프로세스와 공유하는 데이터에 접근, 갱신할 수 있는 코드 부분을 Critical Section이라고 한다. 따라서 동시에 서로 다른 프로세스들이 Critical Section에서 수행되는 일은 없어야 한다!

이러한 문제를 해결하기 위해서는 3가지 조건을 충적해야 한다. 하나씩 알아보자. 

 

Mutual Exclusion

No Race Condition! 한 프로세스가 자신의 critical section에서 실행 중이면, 다른 프로세스들은 자신들의 critical section 들어가서는 안된다!

 

Progress

Process that wants to enter the critical secton will eventually succeed. 현재 Critical section에서 실행중인 프로세스가 없고, 어떤 프로세스가 Critical section에 진입하고 싶어한다면, 최대한 빨리 들여보내 줘야한다!

 

Bounded Waiting

Fairness of admission. 한 프로세스가 자신의 Critical section에 진입하려고 요청한 후, 그 요청 허용될 때까지 타 프로세스들의 Critical section 진입 횟수는 한계가 있어야 한다. 즉 공평하게 Critical section에 들여보내줘야 한다. 

 

단일 코어 시스템이라면 그저 공유 변수 수정중이면 interrupt를 disable해 해결할 수 있다. 

멀티 코어 시스템 + 비선점형 커널이라면 선점을 허용하지 않는 프로세스 스케줄링 특성상 Race condition이 발생할 일 조차 없다. 

하지만 우리는 멀티 코어 시스템 + 선점형 커널을 사용하고 있다. 이게 빠르기 때문이다.

그러면 이 문제를 어떤 방식으로 해결해서 우리는 컴퓨터를 쓰무쓰하게 쓰고 있는 것일까? 알아보자. 

 

2부에 계속...

 

반응형

댓글