[운영체제] 14. Process Synchronization 3

이건회·2022년 3월 20일
0

운영체제

목록 보기
13/27

-Synchronization 환경에서 생기는 여러 가지 문제가 있다

  • 먼저 bounded buffer 문제다. 버퍼의 크기가 유한한 환경이다. 여러 가지 프로듀서-컨슈머 프로세스들이 존재한다. 프로듀서는 공유 버퍼에 데이터를 만들어 집어 넣는 역할을 한다. 주황색이 프로듀서가 데이터를 집어 넣은 상태를 의미한다. 소비자는 데이터를 꺼내 가는 역할을 한다.
  • Synchronization에서 생기는 문제는 공유 버퍼이므로 생산자가 동시에 둘이 도착해서 비어있는 버퍼에 동시에 데이터를 집어넣는 문제가 생긴다. 또 한 데이터에 두 컨슈머가 도착해서 동시에 데이터를 꺼내려는 문제가 있다.
  • 따라서 컨슈머가 데이터를 꺼내 가거나 프로듀서가 데이터를 넣을 때 lock을 이용해 배타적 접근을 한다.
  • 또 공유버퍼가 다 찬 상황에 생산자가 또 도착해 데이터를 집어넣으려 하면 생산자가 사용할 수 있는 자원이 없는 상태가 된다. 즉 생산자에게 자원은 "비어있는 버퍼"를 의미한다. 따라서 소비자가 데이터를 가져가 빈 버퍼가 생길 때까지 기다린다.
  • 반대로 소비자 입장에서는 "내용이 있는 버퍼"가 자원을 의미한다. 따라서 생산자에 의해 데이터가 있는 버퍼가 생길 때 까지 기다려야 한다.
  • 위 사진의 절차에 따라 프로듀서-컨슈머 프로세스가 동작한다.
  • 공유데이터는 버퍼와 버퍼를 조작하는 변수이고, Synchronization 변수는 lock을 풀거나 자원의 개수를 세는 변수다.

  • semaphore 변수를 슈도 코드로 작성한 것이다. 빈 버퍼의 수가 n개, 내용이 있는 버퍼가 0, mutex가 lock을 거는 변수다.
  • 프로듀서는 빈 버퍼를 확인하고 빈 버퍼가 있으면 lock을 걸고 데이터를 집어넣는다. 내용이 있는 버퍼를 1 증가시킨다.
  • 컨슈머는 내용이 있는 버퍼가 있는지 연산을 수행하고 내용이 있는 버퍼가 있으면 버퍼에 lock을 걸고 데이터를 꺼내간 후 Lock을 푼다. 이후 비어있는 버퍼를 1 증가시킨다.

  • 리더-라이터문제는 읽는 프로세스와 쓰는 프로세스 두 가지가 있다. 여기서 공유 데이터를 DB라 부른다.
  • db에 여러 프로세스가 동시에 접근하지 못하도록 lock을 거는 방식으로 하는데, 쓰는 작업은 동시에 하면 안되지만, 읽는 작업은 동시에 접근해도 상관이 없다.
  • 그래서 쓰는 동안에는 lock을 걸어 접근은 막지만 읽고 있을 때는 접근할 수 있도록 해야 한다.

  • 공유 데이터에 P연산을 통해 lock을 건 상황이다.
  • Writer의 경우 전통적인 방식으로 lock을 진행해도 되지만 Reader의 경우 readcount라는 변수를 주어 몇 명이 읽고 있는지를 나타낸다. 따라서 본인이 처음 데이터를 읽으러 들어오면 Readcount를 1로 만들고 db에 lock을 걸고, 누군가가 읽고 있는 상황에서 들어오면 readcount를 증가시키지만 db에 이미 lock이 걸려 있으므로 lock은 걸지 않고 db를 읽기만 한다. readcount 변수는 공유 변수이므로 문제가 발생할 수 있다. 따라서 readcount를 컨트롤하기 위해서도 lock을 걸 필요성이 있다. db를 읽는 작업이 끝났는데, 본인이 마지막으로 읽고 나가는 프로세스라면 db의 lock을 풀고 나간다.
  • 공유데이터는 DB 자체와 readcount, Synchronization 변수는 readcount에 lock을 거는 용도인 mutex와 DB에 lock을 거는 용도인 small db다.
  • Reader가 너무 많이 접근해서 Writer에 starvation이 발생할 수 있다.

  • 마지막은 "식사하는 철학자" 문제다. 다섯 명의 철학자가 생각을 하거나 밥을 먹는다.
  • 철학자가 배가 고프면 왼쪽과 오른쪽의 젓가락을 집어 밥을 먹고, 배가 안 고프면 생각하는 과정을 무한 반복한다.
  • 한 명이 왼쪽을 잡고 싶은데 젓가락이 공유자원이므로 왼쪽 철학자가 이 젓가락을 잡아버리면 놓을 때 까지 기다려야 한다.
  • 식사하는 철학자는 세마포어를 이용해서 아래 구현한 것이다.

  • 모두 동시에 배가 고파 각각 오른쪽의 젓가락을 모두 잡으면 데드락이 발생한다. 이 때 제한된 수의 철학자만 앉게 하거나, 또 양쪽의 젓가락을 확실히 잡을 수 있을 때만 젓가락을 집는 권한은 주는 방법, 혹은 비대칭으로 짝수 철학자는 왼쪽부터, 홀수 철학자는 오른쪽부터 집도록 규정한다.

  • 위 코드가 양쪽 젓가락을 확실히 잡을 수 있을 때만 젓가락을 잡는 구조다. 다섯명의 철학자가 먹거나,배고프거나,생각하는 상태가 존재한다. self는 0과 1에 따라 젓가락을 잡을 수 있는 권한을 의미한다. 인덱싱을 통해 몇 번 철학자에 의한 권한인지 명시한다. 또 젓가락을 잡는것이 서로에게 영향을 주는 공유변수이므로 lock을 위한 mutex변수를 둔다.
  • 코드는 젓가락을 잡고, P연산으로 lock을 건 후 자신 상태를 hungry로 한다. 이후 철학자 i가 지금 젓가락을 잡을 수 있는 상태인지를 test함수로 확인한다. test를 통해 확인 후 V연산을 통해 젓가락 접근 권한을 얻으면 P(self[i]) 연산으로 lock을 걸고 젓가락을 잡는다.
  • 만약 test 연산에서 옆의 누군가가 밥을 먹으면 권한을 얻지 못하고 test가 끝난다. 이 경우에는 P연산을 해도 권한이 생길 때 까지 기다려야 한다.

  • 세마포어의 문제점은 다음과 같다. 한번의 실수가 연쇄적으로 영향을 끼치므로 문제가 생겼을 때 버그를 잡기 쉽지 않다.
  • 모니터를 이용해 위 문제를 해결할 수 있다.

  • 모니터는 어떤 공유 데이터를 접근하기 위해 모니터라고 정의된 내부 절차를 통해서만 접근하도록 한 것이다.

  • 예를 들어 위와 같은 공유 데이터가 있을 때, 모니터 안에 공유 데이터와 데이터 접근 절차를 정의해놓고 그 절차를 통해서만 접근하게 한다. 또 모니터가 모니터에 대한 동시 접근을 허용하지 않고 여러 절차가 동시에 실행되지 않도록 컨트롤 한다. 이 경우 lock을 걸 필요가 없어진다. 이 점이 세마포어에 비해 편리한 점이다.

  • 세마포어에서는 자원의 개수를 세는 절차가 필요했다. 이 과정 역시 모니터에서도 필요한데, 이를 위해 condition 변수를 모니터에 둔다. 만약 x에 여분이 있으면 접근, 여분이 없으면 웨이팅 큐에 기다리는 함수를 정의하고, 접근을 다 하고 빠져나가면 signal을 호출해 기다리고 있는 프로세스가 있으면 깨울 수 있도록 한다.

  • 이전의 세마포어 코드를 모니터 코드로 변환한 것이다. 모니터에서는 lock이 필요 없으므로 생산과 소비 작업을 할때 굳이 lock 없이 그냥 모니터 내부 코드로 실행하면 된다. 생산자 입장에서 비어있는 버퍼가 없으면 줄 서서 기다리도록 하고, 있다면 버퍼에 내용을 넣는다. 작업이 끝나면 내용이 있는 버퍼를 기다리는 소비자 프로세스를 깨운다. 반대로 소비자 입장에서 내용이 있는 버퍼가 없으면 줄을 서게 하고, 내용이 있는 버퍼가 생기면 그 데이터를 꺼내고, 비어있는 버퍼를 기다리는 생산자 프로세스를 깨운다.
profile
하마드

0개의 댓글