{"componentChunkName":"component---src-templates-blog-post-js","path":"/Operating-Systems/2020-05-21-운영체제-유한버퍼문제/","result":{"data":{"site":{"siteMetadata":{"title":"Hun's Footsteps 🥷","author":"전여훈","siteUrl":"https://jeonyeohun.netlify.app","comment":{"disqusShortName":"","utterances":"jeonyeohun/jeonyeohun.github.io"},"sponsor":{"buyMeACoffeeId":"jeonyeohun"}}},"markdownRemark":{"id":"596dabff-a293-5a16-bba0-64222aabf5e8","excerpt":"참고도서: Operating System Concepts (10/E) Abraham Silberschatz, Peter B. Galvin, Greg Gagne…","html":"<p>참고도서: <em>Operating System Concepts (10/E) Abraham Silberschatz, Peter B. Galvin, Greg Gagne</em></p>\n<h2 id=\"다시-찾아온-생산자-소비자-문제\" style=\"position:relative;\"><a href=\"#%EB%8B%A4%EC%8B%9C-%EC%B0%BE%EC%95%84%EC%98%A8-%EC%83%9D%EC%82%B0%EC%9E%90-%EC%86%8C%EB%B9%84%EC%9E%90-%EB%AC%B8%EC%A0%9C\" aria-label=\"다시 찾아온 생산자 소비자 문제 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>다시 찾아온 생산자-소비자 문제</h2>\n<p>이전에 공부했던 생산자 소비자 문제가 다시 찾아왔다. 생산자-소비자 문제 혹은 유한 버퍼 문제는 어떤 버퍼에 생산자는 계속해서 자원을 넣으려고 하고, 소비자는 계속해서 자원을 빼내려고 할 때, 효과적으로 이 둘의 행동을 제어하는 문제이다. 세마포어를 통해 생산자 소비자 문제를 해결하기 위해 우리에겐 다음과 같은 자료구조가 필요하다</p>\n<div class=\"gatsby-highlight\" data-language=\"cpp\"><pre class=\"language-cpp\"><code class=\"language-cpp\"><span class=\"token keyword\">int</span> n<span class=\"token punctuation\">;</span>\nsemaphore mutex <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>  <span class=\"token comment\">// 사호배제를 위한 임계구역 진입여부 표시</span>\nsemaphore empty <span class=\"token operator\">=</span> N<span class=\"token punctuation\">;</span>  <span class=\"token comment\">// 비어있는 버퍼의 자리 개수</span>\nsemaphore full <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>   <span class=\"token comment\">// 차있는 버퍼의 자리 개수</span></code></pre></div>\n<p>우리가 가지고 있는 유한한 버퍼의 크기가 N일 때, 소비자는 버퍼에서 한번의 하나의 자원을 획득해간다. 이때 empty semaphore는 빈자리가 하나 늘어났기 때문에 1 증가하고, full semaphore는 차 있던 버퍼 한 자리가 비워졌기 때문에 1 감소한다.</p>\n<p>세마포어로 유한 버퍼 문제를 구현해보자</p>\n<h2 id=\"생산자producer\" style=\"position:relative;\"><a href=\"#%EC%83%9D%EC%82%B0%EC%9E%90producer\" aria-label=\"생산자producer permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>생산자(Producer)</h2>\n<div class=\"gatsby-highlight\" data-language=\"cpp\"><pre class=\"language-cpp\"><code class=\"language-cpp\"><span class=\"token keyword\">do</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">/* 자원 생성 */</span>\n\n    <span class=\"token function\">wait</span><span class=\"token punctuation\">(</span>empty<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 빈자리가 생길 때까지 대기한다</span>\n    <span class=\"token function\">wait</span><span class=\"token punctuation\">(</span>mutex<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 임계구역 진입이 획득될 때까지 대기한다</span>\n\n    <span class=\"token comment\">/* 버퍼에 자원 넣기 */</span>\n\n    <span class=\"token function\">signal</span><span class=\"token punctuation\">(</span>mutex<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 임계구역 진입 lock을 푼다</span>\n    <span class=\"token function\">signal</span><span class=\"token punctuation\">(</span>full<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>  <span class=\"token comment\">// 버퍼에 새로 들어간 자원이 있다는 것을 알린다.</span>\n\n<span class=\"token punctuation\">}</span> <span class=\"token keyword\">while</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>Producer의 역할을 자원을 버퍼에 넣는 것이다. 이런 맥락에서 위 코드를 해석해보면 Producer가 하는 일의 과정은 다음과 같다.</p>\n<ol>\n<li>버퍼에 넣을 자원 정하기</li>\n<li>버퍼에 빈자리가 있는지 확인, 빈자리가 없다면 대기</li>\n<li>빈자리가 생기면 <code class=\"language-text\">lock 획득</code> 후 임계구역 진입</li>\n<li>임계구역 내에서 버퍼에 자원 넣기</li>\n<li>임계구역 탈출</li>\n<li>임계구역을 빠져나오면서 <code class=\"language-text\">lock 해제 및 full signal 실행</code></li>\n</ol>\n<p>결국 생산자가 하는 역할은 빈자리가 생겼을 때 넣을 자원을 준비해두고 빈자리가 생길때까지 대기하다가 빈자리가 생기는 순간에 임계구역으로 진입해서 빈자리에 자원을 넣어주는 것이다.</p>\n<h2 id=\"소비자consumer\" style=\"position:relative;\"><a href=\"#%EC%86%8C%EB%B9%84%EC%9E%90consumer\" aria-label=\"소비자consumer permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>소비자(Consumer)</h2>\n<div class=\"gatsby-highlight\" data-language=\"cpp\"><pre class=\"language-cpp\"><code class=\"language-cpp\"><span class=\"token keyword\">do</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">wait</span><span class=\"token punctuation\">(</span>full<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>  <span class=\"token comment\">// 자원 대기</span>\n    <span class=\"token function\">wait</span><span class=\"token punctuation\">(</span>mutex<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// lock 획득</span>\n    <span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span>\n    <span class=\"token comment\">/* 버퍼에서 자원 하나 가져오기. 해당 버퍼는 비워진다. */</span>\n    <span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span>\n    <span class=\"token function\">signal</span><span class=\"token punctuation\">(</span>mutex<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// lock 해제</span>\n    <span class=\"token function\">signal</span><span class=\"token punctuation\">(</span>empty<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 자원을 하나 가져갔기 때문에 버퍼에 빈자리가 생겼다는 것을 알린다.</span>\n\n    <span class=\"token comment\">/* 가져온 자원을 사용한다 */</span>\n\n<span class=\"token punctuation\">}</span> <span class=\"token keyword\">while</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>Consumer 의 역할은 버퍼에 남아있는 자원이 있다면, 해당자원을 버퍼에서 꺼내 가져오는 것이다. 이 맥락에서 위 코드를 읽어보면 Consumer의 작업은 다음과 같은 과정으로 이루어진다.</p>\n<ol>\n<li>full semaphore를 읽어서 버퍼에 자원이 있는지 확인</li>\n<li>자원이 있다면 계속 진행, 자원이 없다면 대기</li>\n<li>자원이 있으면 <code class=\"language-text\">lock</code>을 획득하고 임계구역으로 진입해서 자원을 하나 소비</li>\n<li>임계구역 탈출</li>\n<li>임계구역을 빠져나오면서 <code class=\"language-text\">lock 해제 및 empty signal 실행</code></li>\n</ol>\n<p>위와 같이 소비자를 구성하게 되면, 소비자는 버퍼가 오나전히 비워져있지 않다면 버퍼에 접근해서 자원을 하나 가져오게되고, 자원이 빠져나갔다는 것을 signal을 통해 알리게 된다.</p>\n<h2 id=\"lock-을-함께-사용하는-이유\" style=\"position:relative;\"><a href=\"#lock-%EC%9D%84-%ED%95%A8%EA%BB%98-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0\" aria-label=\"lock 을 함께 사용하는 이유 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>lock 을 함께 사용하는 이유</h2>\n<p>위 자료구조에서 세마포어가 총 세 개가 사용된다. 비어있는 버퍼의 갯수를 나타내는 <code class=\"language-text\">empty</code>, 차 있는 버퍼의 갯수를 나타내는 <code class=\"language-text\">full</code> 그리고 프로세스간 상호 배제를 위해 사용하는 <code class=\"language-text\">mutex</code>이다. 세마포어 변수의 이름이 <code class=\"language-text\">mutex</code> 로 지어져서 헷갈릴 수도 있지만, 이 변수는 binary semaphore이지 mutex lock은 아니다. 근데 왜 굳이 lock 역할을 하는 세마포어가 또 필요할끼?</p>\n<p>문제는 full 과 empty의 signal 과 wait 연산에 있다. 두 연산은 그 자체로는 전혀 atomic 한 연산이 아니다. 내부적으로 값도 증가시켜주어야 하고, 대기를 시킬 때는 리스트에 PCB를 연결해주는 것 까지 해야한다. 따라서 signal 에 의해 동시에 여러 프로세스들이 임계구역 진입에 대한 조건을 만족하게 되면, 저마다 대기 큐에서 빠져나오려고 할 텐데, 이 때 binary semaphore를 사용해서 단 하나의 프로세스에게만 진입을 허용한다면, 동시에 여러 프로세스가 임계구역으로 진입하는 문제를 막을 수 있을 것이다.</p>","frontmatter":{"title":"[운영체제] 고전적 동기화 문제-1 : 유한 버퍼 문제(The Bounded-Buffer Problem)","date":"May 22, 2020"}}},"pageContext":{"slug":"/Operating-Systems/2020-05-21-운영체제-유한버퍼문제/","previous":{"fields":{"slug":"/Operating-Systems/2020-05-21-운영체제-식사하는-철학자-문제/"},"frontmatter":{"title":"[운영체제] 고전적 동기화 문제-3 : 식사하는 철학자 문제(The Dining-Philosophers Problem)","category":"Operating-Systems","draft":false}},"next":{"fields":{"slug":"/Operating-Systems/2020-05-21-운영체제-Readers-Wirters-문제/"},"frontmatter":{"title":"[운영체제] 고전적 동기화 문제-2 : 독자와 저자 문제(The Readers-Writers Problem)","category":"Operating-Systems","draft":false}}}},"staticQueryHashes":["2486386679","3128451518"]}