CS

뮤텍스와 세마포어

제주말차아몬드 2024. 8. 18. 22:39

 

프로세스 동기화프로세스들 사이의 수행시기를 맞추는 것을 의미합니다. 여기서 프로세스들 사이의 수행 시기를 맞춘다는 의미는 또 크게 2가지 뜻으로 쓰입니다. 

1. 실행 순서 제어를 위한 동기화 : 특정 조건이 충족되어야만 프로세스가 실행을 이어 나간다. 

writer 프로세스와 reader 프로세스가 동시에 실행 중이라고 가정할 때 두 프로세스는 아무 순서대로 실행 돼서는 안된다. reader 프로세스는 ‘book 안에 값이 존재한다’ 는 특정 조건이 만족 되어야만 실행을 이어나갈 수 있다.

2. 상호 배제를 위한 동기화 : 공유 자원에 대한 동시 접근을 방지하는 것.

아래 와 같이 프로세스 A,B가 존재합니다.

프로세스 A ( 계좌 잔액을 읽음 → 읽어 들인 잔액에서 2만원을 더함 → 더한 값을 저장)
프로세스 B ( 계좌 잔액을 읽음 → 읽어 들인 잔액에서 5만원을 더함 → 더한 값을 저장)

 

현재 잔액이 10만원이고 프로세스 A 와 B가 동시에 실행되었다고 가정해볼까요?  실행 결과 17만원이 계좌에 남을 것이라고 생각하지만 동기화가 이루어지지 않은 경우 엉뚱한 결과가 나올 수 있습니다. 왜냐하면 A와 B는 잔액이라는 데이터를 동시에 사용하기 때문이죠 ! 이처럼 잔액과 같은 동시에 접근해서는 안되는 자원을 동시에 접근하지 못하도록 해야합니다.

그렇다면 동시에 접근해서는 안되는 자원이란 무엇일까요?

위 예시에서 프로세스들이 "잔액"과 같은 공유 자원을 동시에 사용하려고 할 때, 여러 프로세스가 동시에 접근하면 문제가 발생할 수 있습니다. 이처럼 두 개 이상의 프로세스가 동시에 접근하면 안 되는 코드 영역을 임계 구역이라고 합니다. 만약 두 개 이상의 프로세스가 동시에 임계 구역에 진입하려고 한다면, 하나의 프로세스는 대기해야 합니다. 여러 프로세스가 동시에 임계 구역에서 실행되려 할 때 발생하는 문제를 레이스 컨디션이라고 합니다.

레이스 컨디션의 발생 예

레이스 컨디션이 발생하는 예로는 다음과 같은 상황들이 있습니다:

  1. 커널 작업을 수행하는 중에 인터럽트가 발생
  2. 프로세스가 system call 하여 커널 모드로 진입하여 작업을 수행하는 도중 문맥 교환이 일어날 때
  3. 멀티 프로세서 환경에서 공유 메모리 내의 커널 데이터에 접근할 때

레이스 컨디션이 발생하는 근본적인 이유는 무엇일까요?

레이스 컨디션이 발생하는 근본적인 이유는, 고급 언어로 작성된 코드가 실행 과정에서 저급 언어로 변환되기 때문입니다. 예를 들어, "총합을 1 증가시키는" 간단한 명령어는 고급 언어에서는 한 줄로 작성되지만, 저급 언어로 변환되면 다음과 같은 여러 단계로 나뉩니다:

  1. 총합 변수를 레지스터에 저장
  2. 레지스터 값을 1 증가
  3. 레지스터 값을 다시 총합 변수에 저장

이러한 여러 단계로 나뉜 코드 실행 중에 문맥 교환이 발생할 수 있어, 프로세스 간의 작업 순서가 엉키며 레이스 컨디션이 발생하게 됩니다.

 

이제 프로세스 동기화를 위해 대표적으로 사용되는 도구들인 뮤텍스와 세마포어에 대해 알아봅시다.

뮤텍스 

뮤텍스는 임계 구역을 잠금으로써 프로세스 간의 상호 배제를 이루는 도구입니다. 뮤텍스는 동시에 접근해서는 안 되는 자원에 대해 오직 하나의 프로세스만 접근할 수 있도록 보장합니다. 이를 위해 lock이라는 전역 변수가 사용됩니다.

  1. 자물쇠 역할 : 프로세스들이 공유하는 전역변수 lock
  2. 임계 구역을 잠그는 역할 : acquire 함수
  3. 임계 구역을 잠금을 해제하는 역할 : release 함수
acquire(){
	while(lock===true) // 만약 임계 구역이 잠겨 있다면
  .... // 임계 구역이 잠겨있는지 반복적으로 확인
  lock =true; // 만약 임계구역이 잠겨있지 않다면 임계 구역 잠금
}
release(){
   lock =false; //임계 구역 작업이 끝났으니 잠금 해제
}

 

 

  • acquire() 함수는 임계 구역에 진입하기 전에 lock 변수를 확인하여, 임계 구역이 잠겨있지 않다면 잠금을 걸고 진입합니다.
  • release() 함수는 임계 구역에서의 작업이 끝난 후 잠금을 해제합니다.
  • acquire와 release를 임계 구역 전 후로 호출해서 하나의 프로세스만 임계 구역에 진입하게 합니다.

 

acquire(); //자물쇠가 잠겨있는지 확인 , 잠겨있지 않다면 잠그고 들어가기
//임계구역
release(); //자물쇠 반환

이 과정에서 프로세스는 lock이 풀릴 때까지 반복적으로 확인하며 기다리는데, 이를 바쁜 대기(busy wait)라고 합니다. 뮤텍스는 상태가 0과 1로만 표현되어 이진 세마포어라고도 불립니다.

세마포어

세마포어는 여러 개의 공유 자원이 있는 상황에서도 적용이 가능한 동기화 도구입니다. 세마포어는 임계 구역에 동시에 진입할 수 있는 프로세스의 개수를 관리합니다.

  1. 임계 구역에 진입할 수 있는 프로세스 개수 : 전역 변수 S
  2. 임계 구역에 들어가도 좋은지, 기다려야 할 지를 알려주는 wait 함수
  3. 임계 구역 앞에서 기다리는 프로세스에게 가도 좋다고 신호를 주는:signal 함수
wait(){
	S--;
	if(S<0){
		//add this process to queue 해당 프로세스 PCB를 대기큐에 삽입
		sleep(); //대기 상태로 접어듬
	}

}
signal(){
	S++;
  if(S<=0) {
		//remove a process p from queue 대기 큐에 있는 프로세스 P 제거
		wakeup(p)	//프로세스 P 를 대기상태에서 준비상태로 만듬
}
}

 

  • wait() 함수는 전역 변수 S의 값을 감소시키며, S가 0보다 작아지면 해당 프로세스를 대기 큐에 추가하고 대기 상태로 전환시킵니다.
  • signal() 함수는 S의 값을 증가시키며, 대기 큐에서 프로세스를 제거하고 준비 상태로 전환시켜 임계 구역에 진입할 수 있도록 합니다.

 

 

wait();
//임계구역
signal();

 

  • wait() 함수는 전역 변수 S의 값을 감소시키며, S가 0보다 작아지면 해당 프로세스를 대기 큐에 추가하고 대기 상태로 전환시킵니다.
  • signal() 함수는 S의 값을 증가시키며, 대기 큐에서 프로세스를 제거하고 준비 상태로 전환시켜 임계 구역에 진입할 수 있도록 합니다.

 

뮤텍스와 세마포어의 차이

  뮤텍스 세마포어
동기화 대상 1개 1개 이상
자원 소유 가능 불가능
해제 여부 소유하고 있는 스레드만(락을 획득한)이 해제 소유하고있지 않는 스레드가 해제
기타 프로세스의 범위를 가지며, 프로세스가 종료될 때 자동으로 없어진다 시스템 범위에 걸쳐있고, 파일 시스템 상의 파일로 존재

 

 

참고: 혼자공부하는 컴퓨터 구조+운영체제