컴퓨터 사이언스

임계영역, 공유자원, Lock, Mutex

woohap 2024. 10. 23. 00:00

임계영역

여러 프로세스 또는 스레드가 공유하는 자원에 접근하는 코드 부분을 의미 
즉, 동시에 둘 이상의 프로세스/스레드가 실행되면 문제가 발생할 수 있는 코드 영역을 의미

공유자원

멀티스레딩 또는 멀티프로세싱 환경에서 둘 이상의 스레드나 프로세스가 
동시에 접근하거나 사용할 수 있는 시스템 자원이나 데이터를 의미 
Ex) 전역변수, 데이터베이스 연결 객체, 파일, 네트워크 소켓, 프린터, 메모리 버퍼, 카운터 변수

큐 또는 스택, 로깅 시스템 등등

락은 하나의 변수이다.
락을 사용하기 위해서는 락 변수를 선언해야 한다. 

** 락 변수는 락의 상태를 나타냄

두 가지 상태

- 사용 가능 상태 ( unlocked, free )
- 사용중 (acquired) 즉, 임계 영역에서 정확히 하나의 쓰레드가 락을 획득한 상태 
락 자료 구조에 락을 보유한 쓰레드에 대한 정보나 락을 대기하는 쓰레드들에 대한 정보 저장 가능 
이러한 정보는 락 사용자는 모름

lock() 함수

락 획득을 시도하는 함수 
만약 어떤 쓰레드도 락을 갖고 있지 않다면, 그 쓰레드는 락을 획득하여 임계 영역 내로 진입한다.
** 이렇게 진입한 스레드를 락 소유자(Owner)라고 부른다.

만약 다른 스레드가 lock()를 호출한다면 사용 중인 동안에는 lock() 함수가 리턴하지 않는다.

unlock() 함수

락이 다시 사용 가능한 상태가 됨 
락을 대기하는 쓰레드가 없다면 락의 상태는 사용 가능 상태로 유지 됨 
만약 대기 중이던 쓰레드가 있다면 락의 상태가 변경되었다는 것을 인지하고 락을 획득하여 임계영역 내로 진입
일반적으로 쓰레드는 프로그래머가 생성하고 운영체제가 제어한다. 
락을 사용하여 쓰레드에 대한 제어권을 일부를 받을 수 있다. 
락으로 코드를 감싸서 프로그래머는 그 코드 내에서는 하나의 쓰레드만 동작하도록 보장할 수 있다.

즉, 임계 영역에 락을 사용하여 한 번에 한 스레드만 접근하도록 구현할 수 있다. 
락을 통해 프로세스들의 혼란스런 실행 순서에 어느 정도를 질서를 부여할 수 있다.

Pthread 락

쓰레드 간 상호배제 기능을 제공하기 때문에 POSIX 라이브러리는 락을 Mutex라고 부른다. 
lock() 호출과 unlock() 호출 사이의 코드를 감싸는 것 즉, 두 호출 사이의 코드가 임계영역이 된다.

상호배제 (Mutex)

한 쓰레드가 임계영역 내에 있다면 이 쓰레드의 동작이 끝날 때까지 
다른 쓰레드에 들어 올 수 없도록 제한하는 것을 의미 

락 전략

1. 거친 전략
    - 하나의 락이 임의의 임계 영역에 진입할 때 사용 
    - 하나의 큰 임계영역
2. 세밀한 전략 
    - 여러 락을 사용하여 한 번에 여러 쓰레드가 서로 다른 락으로 보호된 코드 내에 각자가 진입 가능 
    - 여러 개의 작은 임계영역

락 동작 평가 기준

1. 상호배제를 지원하는가
    - 락이 동작하여 임계 영역 내로 다수의 쓰레드의 진입을 막을 수 있는지 검사
2. 공정성 
    - 락 획득에 대한 공정한 기회가 주어지는가  ?? // 기아 상태가 발생하지 않는가 ?
3. 성능 
    - 락 사용 시간적 오버헤드 평가

인터럽트 비활성화

** 단일 프로세스 환경에서 인터럽트를 막으면, 임계영역 내의 코드에서는 
   인터럽트가 발생할 수 없기 때문에 원자적으로 실행될 수 있다.  
// pintOS는 단일 프로세스 환경

→ 인터럽트 비활성을 통한 동기화 // 원자성 보장, 간단한 구현, 경쟁 상태 방지, 데드락 방지 
즉, 다른 쓰레드가 중간에 끼어들지 못해 동기화 효과가 발생하여 원자적 실행, 경쟁상태와 데드락 방지 효과가 발생 

- 원자적 실행 : 인터럽트가 비활성화되면, 문맥교환이 발생하지 않아 
  현재 실행 중인 코드는 중단 없이 실행됨
- 경쟁 상태 방지 : 다른 쓰레드나 인터럽트 핸들러가 공유자원에 접근 불가하므로, 
  동시 접근으로 인한 경쟁 상태 방지  
- 데드락 방지 : 인터럽트가 비활성되었기에 컨텍스트 스위칭이 일어나지 않는다. 
  따라서 여러 쓰레드가 서로의 자원을 기다리며 교착 상태에 빠질 가능성이 줄어든다.
- 동기화 효과 : 인터럽트 비활성화는 전체 시스템에 대한 “거대한 락”을 거는 것과 유사한 효과 발생

### 단점
1. 응용 프로그램을 너무 많이 신뢰해야 함 
    → 탐욕적 기법을 사용한 프로그램이 시작과 동시에 락을 걸면 프로세서를 독점적으로 사용


2. 멀티프로세서에서는 적용 불가 
    → 여러 쓰레드가 여러 CPU에서 실행 중이면 각 쓰레드가 동일한 임계영역에 진입 시도할 수 있음
    → 특정 프로세서에서의 인터럽트 비활성화는 다른 프로세서에서 실행 중인 프로그램에는 전혀 영향을 주지 않는다. 

3. 장시간 인터럽트 중지로 인해, 중요한 인터럽트 시점을 놓칠 수 있다. 
    Ex) CPU가 저장 장치에서 읽기 요청을 마친 사실을 모르고 지나가게 되고 OS는 이 읽기 결과를 기다리는 프로세스를 깨울 수 없게 된다. 

4. 비효율적인 방법이다. 
    → 인터럽트 비활성화 코드들이 최신 CPU들에서는 느리게 실행되는 경향이 있음 

**
그러므로 상호배제를 위한 인터럽트 비활성화는 제한된 범위에서만 사용되어야 한다.
- 운영체제가 내부 자료 구조에 대한 원자적 연산을 실행하는 경우
- 복잡해 보이는 인터럽트 발생을 방지하는 경우

'컴퓨터 사이언스' 카테고리의 다른 글

경쟁상태(Race Condition)  (0) 2024.10.25
세마포어  (0) 2024.10.24
프로세스와 스레드  (0) 2024.10.22
CDN  (1) 2024.10.20
파일 디스크립터  (1) 2024.10.18