[OS] 22-1. Locks (1)

Park Yeongseo·2024년 1월 23일
1

OS

목록 보기
24/54
post-thumbnail

Operating Systems : Three Easy Pieces를 보고 번역 및 정리한 내용들입니다.

1. Locks: The Basic Idea

지금은 간단하게 다음의 코드가 임계 영역이라 하자.

balance = balance + 1;

락을 사용하기 위해서는 다음과 같이 임계 영역의 주변을 몇 가지의 코드로 둘러싸면 된다.

lock_t mutex;
...
lock(&mutex);
balance = balance + 1;
unlock(&mutex);

락은 특정 시점의 락의 상태를 나타내는 변수다.이 상태에는

  • 어떤 스레드도 락을 소유하고 있지 않아 사용 가능한 상태(available, unlocked, free)
  • 특정한 한 스레드가 락을 가지고 있는 상태(acquired, locked, held)

가 있다. 이외에도 어떤 스레드가 락을 가지고 있는지, 락 획득 순서를 위한 큐 등의 다른 정보들도 저장할 수 있지만, 이러한 정보들은 락의 사용자에게는 감추어져 있다.

lock()unlock() 루틴이 의미하는 바는 간단하다.

  • lock()
    - 락을 얻으려 시도한다. 만약 어떤 스레드도 락을 가지고 있지 않은 상태라면 스레드는 락을 얻고 임계 영역으로 진입한다.
    - 이렇게 락을 얻은 스레드를 락의 소유자(owner)라 한다.
    - 만약 이때 다른 스레드가 해당 락 변수에 대해 lock()을 호출하면, 이는 락이 다른 스레드에 의해 소유되고 있는 동안에는 리턴하지 않는다. 한 스레드가 락을 쥐고 있는 동안 다른 스레드들이 임계 영역에 진입하는 일을 막기 위함이다.
  • unlock()
    + 락의 소유자가 소유권을 포기한다. 이때 락은 다시 사용 가능해진다.
    + 만약 다른 어떠한 스레드도 락을 기다리고 있지 않다면(즉 어떤 스레드도 lock()을 호출해 대기 중인 상태가 아니라면), 락의 상태는 그냥 사용 가능한 상태로 유지된다.
    + 만약 대기 중인 스레드들이 있다면, 그 중 하나가 락의 상태 변화를 알아차리고, 락을 얻고, 임계 영역에 진입하게 된다.

스레드는 보통 프로그래머에 의해 생성되지만, 제어까지 프로그래머가 하기보다는 OS 스케줄링에 맡기는 경우가 많다. 락은 그러한 제어 중 일부, 그러니까 스케줄링에 대한 최소한의 제어를 프로그래머들에게 다시 돌려준다. 락을 이용하면 하나보다 많은 스레드들이 동시에 임계 영역의 코드를 실행하지 못하도록 보장할 수 있으며, 따라서 전통적 OS 스케줄링이 가져다 주던 혼란을 좀 더 제어된 활동으로 바꿔준다.

2. Pthread Locks

POSIX 라이브러리에서는 락을 뮤텍스(mutex)라 부른다. 다음과 같은 POSIX 스레드 코드를 보면, 정확히 위에서와 같은 동작을 한다는 것을 알 수 있다.

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

Pthread_mutex_lock(&lock); // wrapper; exits on failure
balance = balance + 1;
Pthread_mutex_unlock(&lock);

위 코드를 보면 lock()unlock()에 락을 변수로 전달하는 것을 볼 수 있는데, 이렇게 하면 다양한 다양한 임계 영역에 따라 다양한 락을 사용할 수 있게 된다. 어떤 임계 영역에 들어가든 상관없이 하나의 큰 락만을 사용하는 것보다, 다른 데이터나 자료 구조에 대해서는 다른 락을 사용하도록 해줘야 더 많은 스레드들이 병행적으로 잠긴 코드에 접근할 수 있게 되기 때문이다.

3. Building A Lock

어떻게 효율적인 락을 만들 수 있을까? 효율적인 락은 적은 비용으로 아래의 속성들을 제공한다. 어떤 하드웨어 지원이 필요할까? OS는 어떤 도움을 줄까?

잘 동작하는 락을 만들기 위해서는 하드웨어와 OS의 도움이 필요하다. 이를 위해 사용할 수 있는 여러 많은 서로 다른 하드웨어 명령어들이 있는데, 이 명령어들의 구현에 대해서는 다루지 않겠지만, 어떻게 이것들을 사용해야 락을 구현할 수 있을지에 대해서는 배우게 될 것이다. 또한 OS가 정교한 락 라이브러리를 완성시키는 데 어떤 도움을 주는지에 대해서도 배우게 될 것이다.

4. Evaluating Locks

락을 만들어 보기전에, 우선은 목표가 무엇이고, 락 구현의 효율성을 어떻게 평가할 수 있는지에 대해 얘기해보자. 락이 (잘) 작동하는지 아닌지를 평가하려면 기본적인 기준을 세워야 한다.

  1. 상호 배제 제공
    • 여러 스레드들이 동시에 임계 영역에 진입하는 것을 방지할 수 있는가?
  2. 공정성
    • 락을 얻기 위해 경쟁하는 각 스레드들은 락을 얻기 위한 공정한 기회를 가지고 있나?
    • 어떤 스레드가 락을 평생 갖지 못해, 기아 상태에 빠져 버리는 경우는 없을까?
  3. (시간적) 성능
    • 락을 사용함으로써 발생하는 시간적 오버헤드에 대한 고려가 필요하다.
    • 락에 대한 경쟁이 발생하지 않는 경우(즉 한 스레드가 락을 얻고 푸는 경우)의 오버헤드는 어떻게 되나?
    • 싱글 코어 시스템의 경우는? 혹은 멀티 코어 시스템의 경우는?
profile
블로그 이전 준비 중

0개의 댓글