남이 읽는 CS/운영체제

[운영체제 4편] 세마포어가 무엇인가

배발자 2022. 3. 15.
반응형

 

 

안녕하세요! 개발자 배씨입니다!! 

저번 시간에 뮤텍스에 대한 포스팅이 길어지면서 분위기 전환 겸 새 게시글로 이어서 작성해요!

 

이번에는 "세마포어"에 대해서 알아보려고해요!  

핵심만 먼저 말하자면 공유자원이 하나 이상일 때 처리하는 동기화 방법입니다. 

"카운팅 세마포어"라고도 불립니다.

 

예를 한번 들어볼게요!

 

뮤텍스의 예와 조금 다르게 식당에 화장실이 3개 존재하고

식당 카운터에 화장실 열쇠가 3개 걸려있다고 생각해보세요!

만약, 화장실 3개가 모두 비어있다면 카운터에는 3개의 열쇠가 있을거에요. 

 

이후, 한명의 사람이 열쇠를 하나 들고 화장실에 들어가게 되면 카운터에는 열쇠 2개가 남았을거에요 

이후, 한명의 사람이 열쇠를 하나 들고 화장실에 들어가게 되면 카운터에는 열쇠 1개가 남았을거에요

이후, 한명의 사람이 화장실에서 나와서 열쇠를 반납하게되면 카운터에는 열쇠가 2개로 늘어났겠죠?

 

세마포어 S 현재 공유 자원에 접근할 수 있는 프로세스/스레드(resource)의 수를 의미해요. 

위의 예시에서 세마포어 S는 카운터에 남아있는 열쇠의 개수겠죠?

 

그리고 저는 지금부터 열쇠를 하나 가져가는 연산을 P 라고 부르고열쇠를 반납하는 연산을 V 라고 부르겠습니다!

 

보통 wait()함수와 signal() 함수라고도 하는데 두 함수는 p와 v라고도 얘기해요

자, 이제 P와 V라는 연산에 대해서 상황을 예로 들어서 설명할게요 

 

여기서 잠깐!

만약 P와 V의 동작이 계속 번갈아 진행하다가 S가 0이 되면 무슨뜻일까요??

 

그쵸! 카운터에 남아있는 열쇠가 없으니까 더이상 사람들이 화장실을 사용을 못한다는 얘기입니다. 

그렇다면 현재 화장실에 있는 사람 중에 사용이 끝난 사람이 열쇠를 반납(V) 해줘야 다음 차례의 사람이 열쇠를

들고 들어갈 수 있겠죠??

 

여기까지 이해하셨다면 거의 다 이해하신겁니다!!

지금까지 예로 들었던 비유를 용어로 접목시켜봅시다.

 

P Operation임계 구역에 들어가기 전에 수행하는 동작이에요. 

S의 값이 3이라면 공유자원이 3개 있으니 P 연산을 통해 S의 값을 2로 만드는 연산을 하는거죠. 

즉, S가 0이 아니라면 S = S - 1 을 한 후 자원을 할당하는 겁니다. 

만약 S가 0 이라면 모든 자원이 사용 중이므로 S 가 1 이상의 값이 될 때 까지 대기하겠죠??

 

V Operation임계 구역에서 나올 때 수행하는 동작이에요

S = S + 1 을 하여 자원이 사용 가능한 상태가 되었음을 나타내는 거죠. 

 

이제 코드를 한번 봐볼게요~ 세마포어 방식에는 "Busy-Waiting", "Block-Wakeup" 방식이 있어요

 

1. Busy-Waiting
 P(S) {
     while S <=0; // 아무것도 하지 않음 (반복문)
     S--;
 }

 V(S) {
     S++;
 }

Spin lock(다른 스레드가 lock을 소유하고 있다면 그 lock이 반환될 때까지 계속 확인하며 기다리는 것)이라고 불리는 Semaphore 초기 버전에서 임계구역에 진입해야하는 프로세스는 진입 코드를 계속 반복 실행해야 하며, CPU 시간을 낭비하게 돼요.

 

즉, 위의 코드에서

 " while S <=0; "

S가 0이하라면 계속해서 반복문만 돌게 되는거죠. 

쉽게 설명하자면, 제가 화장실에서 볼일을 보고있는데 밖에서 누가

 

"똑똑.똑똑..똑똑똑똑..똑.똑.똑똑..똑똑똑..똑.똑.똑똑똑똑똑..똑.똑.똑똑..(반복)" 

 

제가 나올때까지 노크를 계~~~~속 하는거랍니다. 이러면 사람 미치겠죠..? 

상당히 비효율적인 방법인거죠.

 

그래서 임계영역에 진입할 때 자원의 값을 감소한 뒤, 만약 자원의 개수가 부족하여 사용할 수 없다면

프로세스를 Wait Queue에 추가하는 방법이 나옵니다. 

 

자원이 부족하면 해당 프로세스를 block()을 통해 Wait Queue에 대기 시키고 자원이 생기면 Wait Queue에서 프로세스를 꺼내와 wakeup()을 통해 프로세스를 수행하는거에요.

 

2. Block-Wakeup

 P(S) {
     S--;
     if S < 0
         // 이 프로세스를 재움 큐에 추가 (잠 듦)
         block(); 
 }

 V(S) {
     S++;
     if S <= 0
         // 재움 큐로부터 프로세스를 제거 (깨어남)
         wakeup(); 
 }

 

이렇게 구현하면 사용중인 화장실에 들어가기 위해 계속 노크하지말고

대기 리스트에 자기 이름을 적고, 자기 차례가 오면 화장실에 들어가게끔 하는거죠. 

이렇게 된다면 Busy waiting으로 인한 시간낭비 문제가 해결될거에요. 


다들 이해하셨죠?? ㅎㅎ 

그러면 이전 포스팅에서 다뤘던 뮤텍스와 지금 다루고 있는 세마포어의 차이점을 아시겠나요?

 

뮤텍스는 공유된 자원에서의 동기화 대상이 하나일때만!!

세마포어는 공유된 자원에서의 동기화 대상이 하나 이상!!

 

 

 

 

근데 여기서 또 문제가 하나 있어요~

 

운영체제를 포스팅하면서 뭐가 이렇게 연결되어있는게 많은지 모르겠어요..ㅠㅠ

그래도 한번 시작한건 끝까지 해야겠죠..?

 

자~ 어떤 문제가 있느냐! 이번에도 간단한 예를 들어볼게요 

 

화가 "배씨"화가 "이씨"가 있어요.

 

그리고 "배씨""이씨"는 그림을 그릴려고 작업실(임계구역)에 들어가서 물감(공유자원), 붓(공유자원)을 

각각 하나씩 집었어요.  

 

"배씨"물감을 들었고 "이씨"을 들고 서로 필요한 도구를 기다리고 있는거에요 

 

"배씨"이 필요하니까 을 기다리고 있고, 

"이씨"물감이 필요하니까 물감을 기다리고 있는거죠. 

 

즉, "둘 이상의 프로세스가 자원을 점유한 상태에서 서로 다른 프로세스가 점유하고 있는 자원을 요구하며 무한정 기다리는 현상"이 발생한다는 거에요!

 

이러한 현상을 "Deadlock(교착상태)"이라고 부릅니다. 

이름부터 살짝 무섭죠???

 

다음 시간에는 Deadlock(교착 상태)가 무엇인지 알아보도록 하겠습니다ㅎㅎ 감사합니다 :)

 

 

 

반응형

댓글