박종훈 기술블로그

모니터와 라이브니스 - 운영체제 6장 동기화 도구

내일은 K-DEVCON Daejeon 스터디 날이다.

스터디는 격주에 한 번씩 모이고 있다. 대전에서 유일하게 CS 지식을 탄탄하게 쌓아나가고 있는 직장인 스터디가 아닐까 싶다.
열심히 하고 관심 있는 사람이 이라면 언제든지 환영이다.

이전 모임 글도 참고용으로 올려본다.
https://k-devcon.tistory.com/entry/Review-2023-10-14-K-DEVCON-DAEJEON-%EC%8A%A4%ED%84%B0%EB%94%94-%ED%9B%84%EA%B8%B0

이번주는 운영체제 6장을 스터디 하기로 계획하였다.
그래서 한번 쭉 읽고 뒤에서 부터 다시 읽으면서 정리해보려고 했는데 깊게보니 생각할 부분이 너무 많아서 한참 걸렸다. 그래서 어쩌다보니 모니터와 라이브니스 파트를 집중해서 보게 되었다.

Blocking NonBlocking 관련된 부분은 항상 어려운 부분인 것 같다. 날 잡아서 한 번 정리하고 가야겠다 싶다.


모니터

모니터 구조물은 모니터 안에 항상 하나의 프로세스만이 활성화되도록 보장해준다. 그러므로 프로그래머들은 이와 같은 동기화 제약 조건을 명시적으로 코딩해야 할 필요가 없다.

모니터 라고 하면 감이 잘 안오는데 java에서는 synchronized 키워드 를 통해서 모니터를 사용할 수 있다. 이렇게 생각하니 나에게는 더 친숙하게 다가왔다.

[Java] 스레드 monitor란? 바이트코드 레벨까지 풀어보신 분의 글이 있어서 링크한다.


만약 wait()를 호출한 프로세스는 다른 프로세스가 signal을 호출할 때까지 일시 중시 되어야 한다고 해보자.

스레드 P에서 signal()을 호출한다고 해보자 이로 인해 일시 중지된 스레드 Q가 실행을 재개하도록 허용된다면, Signal을 보낸 스레드 P는 반드시 대기해야 한다. 그렇지 않으면, P와 Q는 모니터 안에서 동시에 활성화 된다.

그러나 두 프로세스는 개념적으로 그들의 실행을 계속 할 수 있다는 사실에 유의해야 한다. 이 상황에서 두 가지 상황이 존재할 수 있다.

  1. Signal and wait. P는 Q가 모니터를 떠날 때까지 기다리거나 또는 다른 조건을 기다린다.
  2. Signal and continue. Q는 P가 모니터를 떠날 때까지 기다리거나 또는 다른 조건을 기다린다.

절충안 P가 Signal을 호출하면 즉시 모니터를 떠난다. 따라서 Q가 즉시 재개된다.

이 부분에 대한 이해가 안 돼서 한참 고민했다.
그러다 위키피디아에 잘 정리가 되어 있다는 걸 발견하였다. 그래서 아랫부분에 내용을 요약해서 정리해 본다. (위키에는 너무 디테일하게 나와있다.) Monitor (synchronization)

Signal and wait

Blocking 방식입니다. 신호를 받을 때 기다리는 스레드가 대기열에 하나 이상 있으면 신호 스레드는 신호를 받은 스레드에 점유를 원활하게 넘겨줍니다.

그 사이에는 다른 스레드가 점유할 수 없습니다.

대기 (wait):
    현재 스레드를 대기열 큐에 넣습니다.
    현재 스레드를 대기(Block) 상태로 이동시킵니다.

신호 보내기 (signal):
    if 만약 대기열 큐에 스레드가 있다면
        큐에서 스레드를 꺼냅니다.
        꺼내진 큐를 다시 실행합니다.
        (꺼내진 큐가 다음에 모니터를 차지합니다.)

Signal and continue

Non Blocking 방식입니다. 신호를 보내도 점유를 잃지 않습니다. 대신 신호를 받은 스레드가 별도의 대기열(e)로 이동됩니다.

대기 (wait):
    현재 스레드를 대기열 큐에 넣습니다.
    스케쥴을 실행합니다.
    현재 스레드를 대기(Block) 상태로 이동시킵니다.

신호 보내기 (notify):
    if 만약 대기열 큐에 스레드가 있다면
        큐에서 스레드를 꺼냅니다.
        별도의 대기열(e)에 넣습니다.

스케쥴 (schedule):
    if 별도의 대기열(e)에 스레드가 있다면
        별도의 대기열(e)에서 스레드를 꺼내고 다시 실행합니다.

시스템이 제대로 작동하는지를 알려면 두 가지 조건을 검사하여야 한다.
첫째, 프로세스들이 모니터를 정확한 순서에 맞추어 호출하는지 검사하여야 한다.
둘째, 비협조적인 프로세스가 액세스 제어 프로토콜을 사용하지 않아서 모니터가 정한 상호 배제 규칙 경로를 무시하여 공유 자원을 직접 액세스하지 않는다는 것을 보장해야 한다.

이렇게 이야기를 하고 17장에서 설명될 추가적인 기법을 사용해서 해결할 수 있다고 하는데 아마 17.4 장을 이야기하는 게 아닐까 싶다. 내용을 일부만 가져와 보면 다음과 같다.

17.4 보호의 영역
한 프로세스는 자기가 접근을 인가받은 자원들만을 접근할 수 있어야 한다. 또한, 어느 때든 프로세스는 자기 일을 완료하기 위하여 현재 필요로 하는 객체들만을 접근할 수 있어야 한다. 이러한 요구인 “need-to-know”(알 필요가 있는) 원칙은 시스템에서 잘못된 프로세스가 유발할 수 있는 피해의 양을 제한하는 데 유용한다.

라이브니스

책에서는 라이브니스를 다음과 같이 설명한다. Liveness refers to a set of properties that a system must satisfy to ensure that processes make progress during their execution life cycle. 라이브니스는 프로세스가 실행 수명주기 동안 진행되는 것을 보장하기 위해 시스템이 충족해야 하는 일련의 속성을 말한다.

Oracle 자바 문서에서 설명하는 Liveness는 다음과 같다. A concurrent application’s ability to execute in a timely manner is known as its liveness. 적시에 실행되는 동시 애플리케이션의 능력을 ‘라이브니스’ 라고 합니다.

다양한 형태의 라이브니스 실패가 존재하는데, 성능과 응답성이 낮은것이 특징이다. 이 책에서는 라이브니스 실패로 이어질 수 있는 두 가지 상황(교착 상태와 우선순위 역전 상황)을 예시로 들었다.

우선순위 역전 라이브니스 문제

예를 들어, 우선순위가 L < M < H 순서인 L, M, H 세 개의 프로세스가 존재한다고 가정하자. (low, medium, high 인 것 같음)

프로세스 H가 세마포 S가 필요하고 이 자원은 현재 프로세스 L에 의해 접근되고 있는 상황을 생각해보자.
보통은 H는 L이 자원의 사용을 마칠 때까지 기다리게 된다.
그러나 이 순간 프로세스 M이 실행 가능 상태가 돼서 프로세스 L을 선점(preemptive)한다고 가정하자.
이렇게 되면 M이 H보다 우선순위가 낮지만 프로세스 H는 L이 자원을 양도할 때까지 기다려야 하는 시간에 간접적으로 영향을 주게 된다. (더 기다려야 된다.)

H는 L뒤에 실행되도록 순서가 정해졌는데, M이 선점하여서 L보다 앞서 실행되게 되었기 때문에
M - L - H 순으로 프로세스가 처리되는 것이다.

이 라이브니스 문제를 우선순위 역전 이라고 부른다. 이 문제는 셋 이상의 우선순위를 가진 시스템에서만 발생한다.

이 문제는 우선순위 상속 프로토콜(priority-inheritance protocol)을 구현하여 해결할 수 있다. 이 프로토콜은, 더 높은 우선순위 프로세스가 필요로 하는 자원에 접근하는 모든 프로세스는 문제가 된 자원의 사용이 끝날 때까지 더 높은 우선순위를 상속받는다. 그리고 자원 사용이 끝나면 원래 우선순위로 되돌아간다.

위 예시에서 우선순위 상속 프로토콜을 사용하면 다음과 같다.
프로세스 L이 임시로 프로세스 H의 우선순위를 상속받는다. 따라서 프로세스 M이 L의 실행을 선점하는 것을 방지한다. 프로세스 L이 자원 R의 사용을 마치면 상속받은 우선순위를 방출하고 원래의 우선순위로 되돌아간다. 자원 R이 이제 가용 상태가 되는데, 이때 M이 아니라 H가 실행된다. (우선순위가 더 높기 때문에)

L이 H의 우선순위를 상속 받는다. 이를 L’ 이라고 하자. L’의 우선순위는 H와 같다. (L’ = H) 따라서 중간에 M이 선점을 하려고 해도 우선순위가 L’보다 낮기 때문에 시도할 수 없다. H도 M보다 높기 때문에 선점할 수 없다. 따라서 L’ - H - M 순으로 프로세스가 처리된다.