티스토리 뷰

운영체제 7

프로세스 관리(4) : 임계구역 문제 및 세마포어 -

 

앞장에서 프로세스 동기화가 필요한 이유에 대해서 설명을 하였다은행계좌 문제를 통해 공통변수인 은행계좌에 대한 동시 업데이트가 발생하면 문제가 발생할 수 있다따라서 우리는 한 번에 한 쓰레드만 업데이트하는 프로세스 동기화가 필요하다이러한 문제를 임계구역 문제라고 한다여러 개의 쓰레드로 이루어진 시스템에서 각각의 쓰레드는 코드의 영역을 가지고 있는데 이 부분을 임계구역이라고 한다임계구역에서는 공통으로 사용하는 데이터를 바꾸거나 테이블을 업데이트하거나 파일을 쓰거나 하는 일을 할 수 있다앞의 은행계좌 문제로 설명을 하면 은행계좌에 대한 영역이 바로 임계구역이 되는 것이다임계구역을 영어로 하면 Critical section인데 Critical이라는 말이 치명적인이라는 것을 뜻한다따라서 임계구역에서 동기화를 진행하지 못하면 치명적인 문제가 발생한다는 것을 의미한다.


임계구역 문제를 해결하기 위해서는 3가지가 만족되어야한다.


3가지에 대한 이해를 위해 은행계좌 문제를 다시 가져와보도록 하자은행계좌 문제를 다시 한 번 요약하자면 부모님과 학생이 있는데 부모님은 은행계좌에 입금을 학생은 출금을 하는 형식을 가지고 있다부모님과 학생은 각각의 쓰레드를 의미한다은행계좌는 앞에서 말했듯 공통적으로 사용하는 데이터가 된다.


첫 번째는 상호배타(Mutual exclusion)이다오류가 일어나지 않기 위해서는 데이터에 대한 업데이트는 한 순간에 오직 한 쓰레드만이 진행할 수 있다는 것이다은행계좌 문제로 보면 부모님이 은행계좌에 돈을 입금하고 있을 시에는 학생은 돈을 인출할 수 없다는 것을 의미한다공통적으로 사용하는 은행계좌라는 데이터에 대한 접근이 상호배타적이기 때문이다반대의 상황도 마찬가지로 적용된다.


두 번째는 진행(Progress)이다두 쓰레드에서 누가 먼저 들어갈 것인가에 대한 결정이 유한 시간 내에 일어나야한다는 조건이다은행계좌에 접근하는 것이 부모님과 학생 사이에서 유한한 시간 내에 누구 하나가 먼저 접근을 하도록 결정을 해야 한다는 것이다.


세 번째는 유한대기(Bounded waiting)이다유한 대기는 쓰레드가 임계구역에 유한 시간 내에 접근을 해야 한다는 것을 의미한다무한한 시간동안 아무도 접근을 하지 않는 경우가 발생해서는 안 된다.


임계구역 문제를 해결하기 위해서는 위의 3가지가 모두 만족하는 방법을 찾아야한다.


프로세스 동기화라고 하는 것은 프로세스의 실행 순서를 제어를 할 수 있다는 것을 의미한다우리는 앞에서 프로세스 단위로 프로그램이 움직이는 것이 아니라 쓰레드 단위로 움직인다는 것을 배웠다그러므로 프로세스 동기화를 쓰레드 동기화라고 생각할 수 있다그래서 다시 말하면 쓰레드를 우리가 원하는 실행 순서에 따라 제어를 할 수 있는 것을 쓰레드 동기화라고 한다실행 순서를 제어를 함으로써 임계구역 문제를 해결할 수 있다따라서 프로세스/쓰레드 동기화는 프로세스 관리에서 가장 중요한 부분 중 하나가 되는 것이다.


동기화를 통해 쓰레드를 제어하기 위해서 도구들이 존재한다세마포모니터맥 등이 있는데 세마포에 대해서 살펴볼 것이다세마포는 동기화 문제(임계구역 문제해결을 위한 소프트웨어 도구이다구조적으로 정수형 변수와 두 개의 동작(P, V)으로 구성되어 있다두 개의 동작은 정수 값을 증가시키거나(V동작검사하는 역할(P동작)을 한다. V동작을 release()라고 하고 P동작을 acquire()이라 한다다른 언어로는 wait과 signal로 표시하기도 한다. P동작을 호출하게 되면 정수 값이 1만큼 감소되고 값이 0보다 작게 되면 세마포에 존재하는 리스트(Queue)에 쓰레드를 넣고 block시킨다. V동작은 정수 값을 증가시키고 리스트에서 쓰레드를 방출한다세마포는 메인 메모리에서 쓰레드가 동작할 때 갈 수 있는 또 다른 루트인데 동기화를 위해 존재하는 것이다여기서 정수 값은 권한의 개수라고 할 수 있다세마포는 동기화의 조건 중에서 상호배타의 역할을 위해서 존재한다.



위의 개념을 예를 들어 한 번 알아보도록 하자처음의 세마포의 정수 값이 1이라고 가정을 해보자그런데 프로그램이 실행될 때 P동작에 대한 명령이 수행되었다그러면 정수 값이 감소하게 되어 0이 된다하지만 0보다 작지 않으므로 쓰레드는 block되지 않는다그러면 해당 쓰레드는 임계구역에 들어가게 된다그런데 이 때 문맥 전환에 의해 다른 쓰레드가 동작을 하는데 또 P동작을 하는 명령이 수행되었다고 하자그러면 정수 값이 1이 된다이렇게 되면 정수 값이 0보다 작아지므로 이 쓰레드는 리스트에 들어가게 되고 block 상태가 된다그러면 임계구역에 들어가지 못하게 된다따라서 하나의 쓰레드가 임계구역에 들어가면 다른 쓰레드는 세마포에 갇히게 되어 임계구역에 들어가지 못하게 되는 것이다상호배타의 역할이 수행된다그리고 다시 문맥전환에 의해 임계구역에 있던 쓰레드가 V동작이 발생하면 정수 값이 증가하게 되어 0이 된다그러면 다른 쓰레드가 리스트에서 방출되어 임계구역에 진입하게 된다













프로세스/쓰레드 동기화는 여러 개의 프로세스/쓰레드가 공통으로 데이터에 접근하려고 할 때 발생하는 문제를 해결하는 방법이다동기화 부분은 스케줄링과 더불어 프로세스 관리에서 매우 중요한 부분을 차지한다세마포는 프로세스/쓰레드 동기화를 위한 도구 중 하나이다앞장에서 세마포의 원리에 대해서 알아보았는데 이번 장에서는 더욱 자세히 세마포에 대해 다루어보도록 하겠다.


쓰레드가 동작하는 공간에는 공통 데이터를 수정할 수 있는 임계구역이 존재한다쓰레드가 동작을 하면서 임계구역에 들어가게 되면 데이터를 수정할 수 있다쓰레드가 코드를 동작하는 도중에 acquire() 명령어가 실행되면 임계구역에 들어가라는 명령이므로 쓰레드가 임계구역에 들어간다임계구역에 있는 쓰레드는 release()라는 명령어가 실행되면 임계구역에서 나오게 된다이러한 명령어들은 쓰레드 안에 작성된 값이다.


여기서 문제가 발생할 수 있는 것은 하나의 쓰레드가 자신의 임계구역에 들어가서 공통으로 사용하는 데이터를 수정하고 있는 상황에서 문맥 전환(context switching)에 의해 다른 쓰레드가 자신의 임계구역에 가서 공통으로 사용하는 데이터를 수정하려고 시도할 때이다이렇게 되면 결과적으로 데이터의 수정이 이상하게 변동될 수가 있다이러한 문제를 임계구역 문제라고 한다.


위와 같은 문제가 발생하지 않게 하는 방법이 바로 상호배타(Multual exclusion)이다그러면 어떻게 상호배타를 만족시킬 수 있게 할 수 있는가이 때 사용하는 도구가 바로 세마포이다세마포는 정수 값을 가지는데 처음에 나타나는 정수는 임계구역에 들어갈 수 있는 쓰레드의 수를 나타낸다한 쓰레드가 acquire() 명령어를 실행해서 임계구역에 들어가게 되었을 때 문맥 전환에 의해 다른 쓰레드가 acquire() 명령어를 실행했다고 하더라도 임계구역에 들어갈 수 없게 막는 공간이 바로 세마포이다.



세마포이 동기화에서 적용되는 동작원리를 상세히 살펴보자. 

세마포는 쓰레드를 보관하는 Queue를 가진다그리고 앞에서 말했듯 정수 값을 가진다여기서는 시작하는 정수 값을 1로 놓고 설명을 하겠다임계구역에 접근 가능한 쓰레드가 하나라는 것을 의미한다임의의 쓰레드가 임계구역에 쓰레드가 존재하지 않을 경우 acquire()명령을 실행할 수 있다세마포는 acquire()명령을 받을 경우 정수 값을 1감소시킨다그리고 정수 값이 0보다 작을 경우 세마포의 Queue에 쓰레드를 block시킨다하지만 지금의 정수 값이 1이였는데 쓰레드가 acquire()명령을 실행한 경우 0이 되므로 세마포의 Queue에 갇히지 않고 바로 임계구역으로 이동하여 명령을 수행한다하지만 컴퓨터의 CPU 할당은 문맥 전환(context switching)에 의해 다른 쓰레드에게 갈수 있다따라서 다른 쓰레드가 문맥 전환에 의해 코드가 실행되게 되었다고 가정하자그런데 이 다른 쓰레드가 또 acquire()명령을 실행을 하게 되면 어떻게 될까두 번째 쓰레드도 임계구역에 들어가고 싶어 한다하지만 임계구역에는 이미 하나의 쓰레드가 존재하고 있으므로 임계구역에 들어가면 안 된다이를 제어하는 것이 바로 세마포이다. acquire()명령이 또 실행되었으므로 세마포의 정수 값이 또 1감소하게 된다그러면 정수 값은 1이 되어 0보다 작은 값을 가지게 된다이렇게 되면 두 번째 쓰레드는 세마포의 Queue에 block을 당해 임계구역에 접근을 하지 못하는 상황이 된다세마포의 Queue에 block을 당한 쓰레드는 혼자 힘으로 풀려나갈 수 없다그렇다면 어떻게 두 번째 쓰레드는 임계구역에 들어갈 수 있는가세마포에서 줄을 서서 잘 기다리고 있으면 다시 문맥 전환에 의해 앞에 먼저 임계구역에 들어간 쓰레드가 release()라는 명령을 수행할 수 있게 되고 이를 통해 임계구역에서 나가고 싶다는 의사를 표시한다그렇게 되면 세마포는 이를 인지하여 정수 값을 1증가시킨다그렇게 되면 정수 값이 0보다 크게 되므로 줄을 서고 있는 쓰레드가 wakeup을 통해 세마포에서 탈출을 하게 된다이렇게 탈출한 쓰레드는 임계구역에 접근을 허가받게 되어 들어가서 데이터를 수정할 수 있게 된다이런 방식으로 동시에 임계구역을 접근할 수 없게 하는 상호배타가 적용이 가능하게 된다.






세마포는 프로세스 실행 순서를 원하는 대로 제어하는 역할로도 사용할 수 있다

이를 Ordering이라고 한다예를 들어 설명해보자프로세스가 P1과 P2가 있다고 하자각각의 프로세스는 각자의 코드를 가지고 있다. P1은 S1이라는 내부 코드를 P2는 S2라는 내부 코드를 가지고 있다고 가장하자그런데 여기서 우리는 CPU 스케줄링과 상관없이 무조건 P1의 S1이 먼저 실행시키고 싶다고 하자그러면 어떻게 코드를 짜야할까우리는 세마포를 도구 사용하면 가능하다세마포는 정수 값과 프로세스 보관을 가지는 도구이다먼저 세마포의 정수 값에 0으로 놓는다초기 값은 허용되는 프로세스의 수이므로 0이면 아무도 허용이 되지 않는다는 것을 의미한다만약 P1이 먼저 실행되면 S1이 먼저 실행이 되므로 우리는 아무런 효과를 주지 않아도 된다하지만 만약 P2가 CPU 스케줄링에 의해 먼저 실행되게 된다면 우리가 의도한 대로 실행이 되지 않는 것이다그래서 우리는 임의로 P2의 실행코드 앞에 acquire()명령을 넣어준다. acquire()명령을 실행하면 세마포의 정수 값이 1감소하게 되어 1이 된다그렇게 되면 세마포의 정수 값이 0보다 작은 값을 가지게 되므로 P2는 세마포의 프로세스 보관 Queue에 block 당하게 된다그러면 뒤의 코드를 실행할 수 없는 상황에 생긴다그렇게 되면 어떻게 되든 문맥전환에 의해 P1이 먼저 실행하게 된다그런데 P2를 영원히 갇혀있게 하면 안 된다따라서 P1의 내부코드 끝부분에 release()명령을 넣는다그렇게 되면 세마포의 정수 값이 1증가하게 되어 다시 0이 된다그러면 세마포에 저장된 P2가 wakeup이 되어 세마포에서 빠져나오게 된다이렇게 세마포를 이용한 명령을 임의로 입력해 넣어 우리가 원하는 프로세스의 처리 순서를 제어할 수 있다.




프로세스 관리(6) : 생산자-소비자 문제 -

 

프로세스 동기화는 프로세스 관리 분야에서 중요한 분야이다앞의 장들은 동기화를 공부하기 위해 은행계좌 문제를 예시로 들어서 설명하였다이번 장은 대표적인 프로세스 동기화에 대한 문제인 생산자-소비자 문제를 설명 할 것이다.


생산자-소비자 문제는 생산자가 데이터를 생상하면 소비자는 그것을 소비하는 형태에서 발생하는 문제를 말한다컴퓨터 세계에서 예를 들면 웹 서버와 웹 클라이언트로 들 수 있다웹 서버가 데이터를 생산하여 웹에 관련되어 보여주는 작업들을 수행하고 웹 클라이언트는 웹 주소로 접속해 화면을 통해 보게 되는 형태의 소비 작용을 한다.


일반적으로 생산하는 속도와 소비하는 속도에 차이가 존재한다실제로 생산되는 속도가 소비하는 속도보다 빠른 경우가 많아서 생산된 데이터는 바로 소비되지 못한다이를 보안하기 위해 생산된 데이터를 보관하는 버퍼라는 공간이 존재한다생산자가 데이터를 생산하면 버퍼에 보관을 하게 되고 소비자는 버퍼에서 데이터를 빼내어 사용한다하지만 현실 시스템에는 버퍼의 크기가 유한하다크기가 정해져 있는 버퍼이기 때문에 Bounded Buffer라고 불린다생산자는 버퍼가 가득 차면 더 이상 넣을 수가 없다반대로 소비자는 버퍼가 비면 뺄 수가 없다.


위와 같은 문제의 키워드를 가지고 자바 코드를 이용해서 작성을 해보자.


우선 버퍼에 대한 클래스를 만들어 버퍼를 정수 값으로 지정을 하였다. size는 버퍼의 크기를 나타내고 count는 버퍼에 들어와 있는 데이터의 개수라고 할 수 있다생산된 데이터가 버퍼로 들어오면 count를 1증가시키고 소비자가 빼어 가면 1감소시킨다. in은 데이터를 넣는 위치를 out은 빼내는 위치를 가리킨다. in 값은 데이터가 들어올 때마다 1씩 증가하고 out 값은 데이터가 나갈 때마다 1씩 증가한다만약 in의 값이 size까지 가게 되면 다시 처음 0의 값으로 돌아가서 데이터를 넣기 시작한다버퍼가 가득 차여져 있으면 out이 실행되기 전까지 무한루프를 돌면서 데이터를 넣지 못하고 기다리고 있는 상태가 된다반대로 버퍼가 비어져 있으면 out은 실행되지 못하고 무한루프를 돌게 되고 in으로 데이터가 들어오기를 기다리게 된다.



생산자와 소비자는 서로 다른 동작을 하는 쓰레드로 제작을 하면 된다생산자의 쓰레드의 경우는 N번 데이터를 생산하여 버퍼에 넣어주는 작업을 소비자의 쓰레드는 N번 데이터를 버퍼에서 가져와 소비하는 작업을 만들어 준다메인함수에서는 100크기의 버퍼를 만들고 N을 만 번으로 지정한다.



위의 코드를 실행하게 되면 당연히 만 번 데이터가 들어가고 만 번 데이터가 나와 결과적으로 버퍼의 count는 0이 되어야 하는데 실행을 해보면 그렇게 되지 않는 경우가 발생하는 것을 알 수 있다또한 실행이 불가한 경우도 발생한다이러한 문제가 발생하는 이유가 바로 쓰레드 동기화가 되지 않았기 때문이다공통변수인 count, buf에 대한 동시 업데이트가 발생하여 값의 변화에 문제가 생긴다공통변수 업데이트 구간인 임계구역에 대한 동시 진입이 가능하므로 데이터의 변화가 따로 발생할 수 있으므로 문제가 발생한다다시 말해 생산자가 count를 올리고 있는 도중에 문맥전환에 의해 소비자가 돌게 되어 count를 낮추는 작업을 하게 되면 count의 값에 오류가 발생하는 것이다.


이를 해결하기 위해서는 임계구역에 대한 동시 접근을 방지하는 상호배타의 기능이 추가되어야한다우리는 앞장을 통해 상호배타를 적용시킬 수 있는 방법을 알고 있다바로 세마포를 이용하여 상호배타를 적용시켜 주는 것이다세마포의 정수 값을 1로 두어 생산자나 소비자 중 하나만이 임계구역에 들어갈 수 있도록 해주어야 한다이렇게 세마포를 만들게 되면 생산자가 데이터를 생산하여 버퍼에 넣어주는 작업을 수행하게 되면 소비자는 데이터를 빼내는 작업을 할 수 없게 된다공통된 값인 count와 buf에 관련된 업데이트가 동시에 되지 않으므로 오류가 발생하지 않는다.


자바 코드에서 수정을 하는 부분은 insert와 remove 공간에서 버퍼의 데이터를 업데이트 해주는 부분을 감싸는 acquire()명령어와 release()명령어를 입력해주면 된다물론 세마포에 대한 정의를 따로 해주어야 한다우리는 이렇게 세마포를 사용하여 프로세스/쓰레드 동기화를 시켜주어 오류를 수정해 줄 수 있다.




하지만 위의 과정은 오류에 대한 수정은 하였지만 기다려야하는 시간이 길어질 수 있다앞의 키워드에서 주어졌듯이 생산자는 버퍼가 가득 차 있으면 기다려야하고 소비자는 버퍼가 비어 있으면 기다려야한다코드를 보면 무한루프를 돌면서 계속 CPU가 할당되어 잡혀있는데 이런 시간은 매우 좋지 않다이런 기다림을 Busy-wait이라고 한다. CPU가 아무 일도 하지 않게 되면 성능이 매우 낭비가 된다이를 해결하는 것도 세마포를 이용해서 할 수 있다세마포의 장점 중 하나는 프로세스나 쓰레드의 실행 순서를 사용자가 원하는 순서에 따라 작업을 수행시킬 수 있게 하는 것이다만약 버퍼가 가득 차여 있으면 세마포의 공간에 생산자를 가두어 CPU가 할당 받지 못하도록 한다이렇게 되면 CPU는 무조건 소비자에게 CPU를 할당할 수밖에 없어 버퍼의 빈 공간을 만들어 주게 된다반대로 버퍼가 비어있으면 CPU할당을 생산자에게 주어 버퍼를 채우게 한다.


이러한 세마포를 재작해보자위와 같은 동작을 하려면 세마포를 두 개를 재작해야한다생산자와 버퍼와의 관계를 제어할 수 있는 세마포(empty)와 소비자와 버퍼의 관계를 제어하는 세마포(full)가 필요하다생산자와 버퍼를 제어하는 세마포는 정수 값의 초기 값을 size 값으로 가지게 된다데이터가 계속 버퍼에 들어가는데 버퍼가 size만큼 들어가게 되면 생산자는 block이 되어야한다반대로 소비자의 세마포는 비어 있을 때 block되어야 하므로 정수 값의 초기 값으로 0을 가진다버퍼에 데이터가 들어오면 정수의 값을 증가시키고 데이터가 없는 빈 버퍼가 되었을 때 acquire()명령으로 데이터를 빼내오려고 한다면 정수 값이 0보다 작은 값을 가지게 되므로 소비자 쓰레드를 block 시킨다두 개의 세마포는 release를 명령을 보내게 되면 상대방의 세마포를 풀어주어 동작을 할 수 있게 한다이렇게 제어를 하게 되면 CPU가 무한 루프를 돌고 있는 작업을 하는 것을 막을 수 있다.




프로세스 관리(7) : 읽기-쓰기 문제식사하는 철학자 문제 -

 

읽기 쓰기 문제는 공통 데이터베이스에 접근하는 문제를 다룬다서버에 데이터베이스가 존재하는데 다른 로컬 컴퓨터들이 데이터에 접근을 할 수 있다접근하는 사용자 중에는 Reader와 Writer가 존재한다. Reader는 데이터를 읽기만 하는 사용자이고 Writer는 데이터를 읽고 수정할 수 있는 사용자를 의미한다데이터베이스를 사용자들이 모두 공통 사용하므로 임계구역이라고 생각할 수 있다.


우리는 앞의 임계구역 문제를 해결하기 위해 동기화를 사용하였는데 상호배타를 만족시키기 만들어 한 번에 한 개의 프로세스만 접근이 가능하게 만들었다임계구역에 데이터를 접근하는 사용자에 접근 권한을 두어 동시에 접근을 할 수 없게 만들었다하지만 위의 읽기 쓰기 예시를 한 번 살펴보면 이런 점이 매우 비효율적이라는 것을 알 수 있다.


만약 사용자 Reader1이 데이터베이스에 접근을 했는데 다른 Reader2가 데이터베이스에 접근을 한다고 문제가 발생할까? Reader는 데이터를 읽기만 하는 사용자를 의미한다따라서 데이터베이스에 접근을 하더라도 데이터의 변형을 만들지 않아 문제를 발생시키지 않는다효율성의 제고를 통해 Reader이 동시에 접근하려고 하면 접근 권한을 주어도 된다그러면 Writer의 경우는 어떨까? Writer는 데이터를 읽기도 하지만 쓰기도 한다즉 데이터의 변형업데이트가 일어난다따라서 Writer 두 사용자가 동시에 접근하면 문제가 발생할 수 있다그러면 Reader가 들어왔는데 Writer가 접근을 하고 싶어 하면 어떻게 될까? Reader가 읽고 있는 데이터가 Writer에 의해 변형업데이트 되므로 문제가 발생할 수 있다. Reader는 제대로 된 데이터를 읽을 수 없기 때문이다.



그러면 어떻게 설계를 해야 할까?


Reader가 데이터베이스(임계구역들어갈 경우다른 Reader는 접근할 수 있으나 Writer는 접근할 수 없다.

Writer가 데이터베이스(임계구역들어갈 경우, Reader와 Writer 모두 접근할 수 없다.

 

위의 문제를 해결하기 위해서는 우선순위를 이용하여 해결할 수 있다. Reader에게 먼저 우선권을 주어 Reader가 접근을 하면 Writer는 반드시 다음으로 실행이 되어야한다.

 

식사하는 철학자 문제는 5명의 철학자가 식사를 하고 있는 상황을 가정한 문제이다철학자들이 원형의 테이블에 앉아 있는데 철학자들 사이에는 젓가락이 놓여있다하지만 젓가락이 한 쌍이 놓여 있는 게 아니라 하나가 놓여있는 상황이다철학자는 생각을 하면서 산다그러다가 배가 고프면 자신의 양 옆에 있는 젓가락을 사용해서 식사를 하고 또 다시 생각을 한다이러한 상황을 가정한 문제가 식사하는 철학자 문제이다여기서 어떤 문제가 발생하겠는가만약 서로 양 옆에 앉아 있는 철학자 같이 배가 고플 경우 어떻게 되겠는가식사하기 위해서는 젓가락을 두 개를 사용해야하는데 한 철학자가 사용할 경우 옆에 앉은 두 명의 철학자는 젓가락을 두 개를 만들지 못해 식사를 할 수 없게 된다따라서 젓가락에 대한 접근을 하는 것에 대한 문제 해결이 필요한 것이다이 문제를 프로그래밍을 통해 해결해보자.



철학자에 대한 정보는 쓰레드와 같다젓가락에 대한 접근은 양 옆 철학자에 대해 공통적인 데이터를 접근하는 것과 같다임계구역에 접근하는 것과 같아 한 명의 철학자가 젓가락 사용즉 임계구역에 접근을 하면 다른 철학자는 그 구역에 접근을 할 수 없다그러면 이와 같은 상황을 세마포를 이용해서 상호배타를 만족시키는 상황을 만들 수 있을 것이다우선 젓가락과 철학자에 대해 번호를 매긴다. 5개의 임계구역(젓가락)이 만들어져야 하고 각 젓가락 자체가 세마포를 이용해서 접근 제한을 만들기 때문이다하나의 젓가락에 대한 세마포는 정수 값의 초기 값으로 1을 가진다철학자 한 명이 접근을 하면 다른 철학자가 접근을 하지 못하므로 1명만 접근을 하게 만들기 위해서이다.


철학자라는 쓰레드는 자신의 고유번호를 가지고 왼쪽 젓가락과 오른쪽 젓가락을 가질 수 있다먹는 동작과 생각을 하는 동작을 가지고 행동을 하게 된다만약 왼쪽 젓가락과 오른쪽 젓가락을 모두 가지게 되면 식사를 하는 동작을 수행하고 그 후 젓가락을 놓고 생각을 하는 동작에 빠지게 된다.


하지만 위와 같은 코드를 실행하면 문제가 발생한다바로 모든 철학자가 식사를 하지 못해 굶어 죽는 상황인 starvation인 상태가 발생할 수 있기 때문이다우리는 철학자에게 명령을 넣어줄 때 왼쪽 젓가락에 대한 접근을 먼저 주었다철학자들은 각자 동작하는 쓰레드이므로 문맥전환이 발생할 수 있다그러면 한 명의 철학자가 왼쪽 젓가락에 대한 접근을 하였을 때 문맥전환이 발생했다고 생각해보자그 때 자신의 오른쪽에 있던 철학자 쓰레드가 동작하여 왼쪽 젓가락을 잡았다고 생각하자그러면 원래 첫 번째로 젓가락을 잡은 철학자 쓰레드의 오른쪽 젓가락을 잡은 것과 같은 상황이다이렇게 되면 첫 번째 철학자 쓰레드는 젓가락이 하나 밖에 없어 오른쪽 젓가락을 잡을 수 있는 상황이 될 때까지 기다린다왼쪽 젓가락을 잡고 있는 채로 말이다그렇게 모든 철학자 쓰레드가 젓가락 하나만 가지고 있는 상태가 되면 프로그램은 돌아가지 않는다아무도 식사를 하지 못한 채로 정지되어 있게 된다이러한 상황을 starvation이 일어났다고 한다. 1번 쓰레드가 2번 쓰레드의 영향으로 실행을 못하는 상황인데 2번 쓰레드는 1번 쓰레드에 의해 실행을 못하게 되면 두 쓰레드 모두 실행을 하지 못하게 되는 상황이다이런 상태를 교착상태라고 한다영어로 Deadlock이다동기화를 세마포를 통해 설계를 하였는데 교착상태에 빠져 모든 자원이 임계구역에 접근을 하지 못하게 되는 것이다.


Deadlock은 다음 장에서 알아보도록 하자.



출처: http://copycode.tistory.com/71?category=740133 [ITstory]


'OS' 카테고리의 다른 글

8. 운영체제 메모리 관리  (0) 2018.11.02
7. 운영체제 교착상태  (0) 2018.11.02
6. 운영체제 프로세스 동기화  (0) 2018.11.02
5. 운영체제 CPU 스케줄링  (0) 2018.11.02
4. 운영체제 스레드  (0) 2018.11.02
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함