{"componentChunkName":"component---src-templates-blog-post-js","path":"/Operating-Systems/2020-05-21-운영체제-Readers-Wirters-문제/","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":"5d77214d-31a9-5125-842e-2c890fa1213c","excerpt":"참고도서: Operating System Concepts (10/E) Abraham Silberschatz, Peter B. Galvin, Greg Gagne 독자와 저자 문제 한국어로 직역해서 독자와 저자라고 했지만, 우리에게 더 편한 데이터베이스를 한번 생각해보자. 독자는 데이터베이스를 read 하는 요청, 저자는 데이터베이스를 write 하는 요청이라고 한다면 우리는 다음과 같은 충돌 상황에 대한 대체가 필요하다. Write 하고 있는 중에 Read가 되는 경우 Write…","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%8F%85%EC%9E%90%EC%99%80-%EC%A0%80%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>한국어로 직역해서 독자와 저자라고 했지만, 우리에게 더 편한 데이터베이스를 한번 생각해보자. 독자는 데이터베이스를 read 하는 요청, 저자는 데이터베이스를 write 하는 요청이라고 한다면 우리는 다음과 같은 충돌 상황에 대한 대체가 필요하다.</p>\n<ol>\n<li>Write 하고 있는 중에 Read가 되는 경우</li>\n<li>Write 하고 있는 중에 또 다른 Write 가 요청된 경우</li>\n</ol>\n<p>위 두가지 충돌 상황을 보게되면 가장 문제를 크게 야기하는 부분이 write라는 생각이 들었을 것이다. 상식적으로 생각했을 때도, 동시에 여러 읽기 작업이 일어나는 것은 데이터의 변형을 일으키지 않으니 전혀 문제가 될 것이 없다. 결국 이 문제를 해결하기 위해서는 다음과 같은 대처가 필요하다.</p>\n<ol>\n<li>Write가 수행되고 있는 동안에는 Read가 접근하지 못하게 한다.</li>\n<li>한번에 하나의 Write 만 접근을 허용한다.</li>\n</ol>\n<p>그럼 이 내용을 세마포어를 이용해서 구현해보자.</p>\n<h2 id=\"자료구조data-structure\" style=\"position:relative;\"><a href=\"#%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0data-structure\" aria-label=\"자료구조data structure 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>자료구조(Data Structure)</h2>\n<p>동기화를 위한 변수는 다음과 같이 사용한다</p>\n<div class=\"gatsby-highlight\" data-language=\"cpp\"><pre class=\"language-cpp\"><code class=\"language-cpp\">semaphore rw_mutex <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\nsemaphore mutex <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">int</span> read_count <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span></code></pre></div>\n<ol>\n<li><code class=\"language-text\">rw_mutex</code> : Writer 와 Reader 사이에 공유되는 변수이다. 공유 데이터에 Writer와 Reader 가 함께 존재하는 경우는 있으면 안되기 때문에 semaphore 값을 1로 초기화 한다. lock을 획득할 수 있는 프로세스의 개수가 최대 한 개라는 뜻이다.</li>\n<li><code class=\"language-text\">mutex</code> : read_count 의 값 갱신이 atomic 하게 일어날 수 있게끔 writer 의 접근을 차단하기 위한 lock이다.</li>\n<li><code class=\"language-text\">read_count</code> : 현재 Read 를 수행하는 프로세스의 개수를 기록하는 변수이다.</li>\n</ol>\n<h2 id=\"writer\" style=\"position:relative;\"><a href=\"#writer\" aria-label=\"writer 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>Writer</h2>\n<p>쓰기 작업을 수행하는 Writer 의 구조는 다음과 같다.</p>\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>rw_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>rw_mutex<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// lock 반납</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<ol>\n<li>Writer는 일단 <code class=\"language-text\">rw_mutex</code>가 사용가능한 상태인지 확인한다. 만약 Reader가 데이터를 읽고 있다면, <code class=\"language-text\">rw_mutex</code>의 값이 음수가 되기 때문에 Writer는 대기하게 된다.</li>\n<li>lock을 획득하게 되면 임계구역으로 진입해서 쓰기 작업을 수행한다. <code class=\"language-text\">rw_mutex</code>는 <code class=\"language-text\">binary semaphore</code>이기 때문에 만약 Writer가 lock을 획득했다면, Reader는 임계구역에 접근할 수 없게된다.</li>\n<li>쓰기 작업을 마치면 signal을 실행하면서 lock을 방출하고 작업을 종료한다.</li>\n</ol>\n<h2 id=\"reader\" style=\"position:relative;\"><a href=\"#reader\" aria-label=\"reader 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>Reader</h2>\n<p>읽기 작업을 수행하는 Reader 의 구조는 다음과 같다.</p>\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>mutex<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>           <span class=\"token comment\">// read_count 의 증가 연산이 다른 프로세스의 영향을 받지 않게 하기 위해 lock 획득</span>\n    read_count<span class=\"token operator\">++</span>            <span class=\"token comment\">// 증가. mutex 세마포어 덕분에 한번에 하나의 증가만 일어난다</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>read_count <span class=\"token operator\">==</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>   <span class=\"token comment\">// read_count 가 1이라면 제일 처음 읽기를 시도하는 프로세스</span>\n        <span class=\"token function\">wait</span><span class=\"token punctuation\">(</span>rw_mutex<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>     <span class=\"token comment\">// Writer 가 작업중인지 확인하고 작업중이면 대기상태로 넣기</span>\n    <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\n    <span class=\"token comment\">/* 읽기 작업 수행 */</span>\n\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\">// read_count 의 값을 줄이기 위해 lock 획득</span>\n    read_count<span class=\"token operator\">--</span><span class=\"token punctuation\">;</span>           <span class=\"token comment\">// 연산 수행</span>\n    <span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span>read_count <span class=\"token operator\">==</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>    <span class=\"token comment\">// 만약 read_count가 0이라면, 현재 읽기 작업을 수행중인 프로세스가 없다</span>\n        <span class=\"token function\">signal</span><span class=\"token punctuation\">(</span>rw_mutex<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>   <span class=\"token comment\">// 대기중인 Writer 에 signal을 보낸다</span>\n    <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 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>Writer 는 매우 직관적이고 단순한 구조였지만, Reader 는 조금 복잡해졌다. 임계구역 앞뒤로 나누어서 과정을 한번 따라가 보자.</p>\n<h3 id=\"읽기-작업-진입-전\" style=\"position:relative;\"><a href=\"#%EC%9D%BD%EA%B8%B0-%EC%9E%91%EC%97%85-%EC%A7%84%EC%9E%85-%EC%A0%84\" 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>읽기 작업 진입 전</h3>\n<div class=\"gatsby-highlight\" data-language=\"cpp\"><pre class=\"language-cpp\"><code class=\"language-cpp\">    <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\">// read_count 의 증가 연산이 다른 프로세스의 영향을 받지 않게 하기 위해 lock 획득</span>\n    read_count<span class=\"token operator\">++</span>            <span class=\"token comment\">// 증가. mutex 세마포어 덕분에 한번에 하나의 증가만 일어난다</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>read_count <span class=\"token operator\">==</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>   <span class=\"token comment\">// read_count 가 1이라면 제일 처음 읽기를 시도하는 프로세스</span>\n        <span class=\"token function\">wait</span><span class=\"token punctuation\">(</span>rw_mutex<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>     <span class=\"token comment\">// Writer 가 작업중인지 확인하고 작업중이면 대기상태로 넣기</span>\n    <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\n    <span class=\"token comment\">/* 읽기 작업 수행 */</span>\n\n    <span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span></code></pre></div>\n<ol>\n<li>다수의 Reader가 임계구역 진입을 시도할 수 있다. 이때 read_count 의 값을 증가시키는 것이 atomic 하게 수행되어야 하는데 <code class=\"language-text\">++</code> 연산은 atomic 한 연산이 아니다.</li>\n<li>따라서 mutex로 lock을 획득해서 read_count 를 한번에 한 프로세스에서만 증가시킬 수 있게 한다.</li>\n<li>read<em>count 를 증가시킨 시점에서 read</em>count의 값이 <code class=\"language-text\">1</code>이라면, 해당 프로세스가 임계구역에 진입하는 <code class=\"language-text\">최초의 Reader</code>임을 의미한다. lock 을 획득해서 read<em>count 값을 올리는 이유가 바로 여기에 있다. 만약 lock이 없었다면 여러 Reader가 read</em>count의 값을 증가시켜서 최초의 프로세스가 누구였는지 판단할 수 없게 될 것이다.</li>\n<li>진입을 시도하는 프로세스가 최초의 Reader 라면 Writer가 작업중일 가능성이 있기 때문에 <code class=\"language-text\">rw_mutex</code> 를 확인해서 Writer가 작업중이라면 Reader를 대기 큐에 넣는다.</li>\n<li>만약 이 프로세스가 읽기를 처음 시작하는 프로세스가 아니라면 이미 임계구역 내에서 읽기 작업을 수행중인 프로세스가 있다는 것이기 때문에 <code class=\"language-text\">rw_mutex</code>를 검사할 필요없이 곧바로 임계구역으로 진입한다.</li>\n<li>임계구역으로 진입하면서 다른 Reader 의 접근을 허용하기 위해 <code class=\"language-text\">signal(mutex)</code>를 실행한다.</li>\n</ol>\n<h3 id=\"읽기-작업-후\" style=\"position:relative;\"><a href=\"#%EC%9D%BD%EA%B8%B0-%EC%9E%91%EC%97%85-%ED%9B%84\" 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>읽기 작업 후</h3>\n<div class=\"gatsby-highlight\" data-language=\"cpp\"><pre class=\"language-cpp\"><code class=\"language-cpp\">    <span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span>\n\n    <span class=\"token comment\">/* 읽기 작업 수행 */</span>\n\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\">// read_count 의 값을 줄이기 위해 lock 획득</span>\n    read_count<span class=\"token operator\">--</span><span class=\"token punctuation\">;</span>           <span class=\"token comment\">// 연산 수행</span>\n    <span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span>read_count <span class=\"token operator\">==</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>    <span class=\"token comment\">// 만약 read_count가 0이라면, 현재 읽기 작업을 수행중인 프로세스가 없다</span>\n        <span class=\"token function\">signal</span><span class=\"token punctuation\">(</span>rw_mutex<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>   <span class=\"token comment\">// 대기중인 Writer 에 signal을 보낸다</span>\n    <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></code></pre></div>\n<ol>\n<li>읽기 작업이 끝나면, Reader는 임계구역을 빠져나오면서 reader_count 를 하나 감소시켜야 한다.</li>\n<li>이때 역시 reader_count 의 감소연산을 atomic하게 만들기 위해 mutex 세마포어를 통해 다른 Reader의 접근을 제한한다.</li>\n<li>reader_count의 값을 하나 줄였을 때 결과 값이 0이 된다면 방금 임계구역을 빠져나온 프로세스가 실행중이던 <code class=\"language-text\">마지막 Reader</code>가 된다.</li>\n<li>따라서 rw_mutex의 값을 증가시켜서 Writer가 lock을 획득할 수 있게한다.</li>\n<li>마지막 Reader가 아니라면 아직 임계구역에서 작업중인 Reader가 있다는 것을 의미하고 Writer 의 접근이 제한되어야 하기 때문에 다른 mutex만 signal 해주고 종료된다.</li>\n</ol>","frontmatter":{"title":"[운영체제] 고전적 동기화 문제-2 : 독자와 저자 문제(The Readers-Writers Problem)","date":"May 23, 2020"}}},"pageContext":{"slug":"/Operating-Systems/2020-05-21-운영체제-Readers-Wirters-문제/","previous":{"fields":{"slug":"/Operating-Systems/2020-05-21-운영체제-유한버퍼문제/"},"frontmatter":{"title":"[운영체제] 고전적 동기화 문제-1 : 유한 버퍼 문제(The Bounded-Buffer Problem)","category":"Operating-Systems","draft":false}},"next":{"fields":{"slug":"/Operating-Systems/2020-05-25-운영체제-모니터/"},"frontmatter":{"title":"[운영체제] 모니터(Monitor)","category":"Operating-Systems","draft":false}}}},"staticQueryHashes":["2486386679","3128451518"]}