본문 바로가기

CS/운영체제(OS)

전통적인 동기화 문제

728x90

은행동기화 문제 같이 우리 실생활에서 사용되는 문제들도 있지만 예전부터 전통적으로 문제가 되는 문제들이 있다. 이를 전통적 동기화 문제라고 한다.

Producer and Consumer Problem

생성자, 버퍼, 소비자

  • 생산자 소비자 문제
  • 생산자는 데이터를 생성하고 소비자는 그 데이터를 소비한다. 예를들어 컴파일러가 데이터를 컴파일하면 어샘블리 코드가 되고 어셈블리어를 번역하여 기계어가 된다.
  • 생산자는 데이터를 생성하고서 바로 소비자에게 넘기지 않는다. I/O차이, 연산차이 등 속도를 맞추기 위해 먼저 buffer에 데이터를 삽입하고 이후 소비자가 버퍼에 접근해 take 하는 식으로 처리된다. 즉, 버퍼는 생산자와 소비자가 모두 접근하는 Critical Section이 되는 것이다. 
    • 이를 해결하기 위해 상호배재를 위한 세마포어를 한개 사용한다.
      • 그렇지 않으면 코드가 실행되지 않거나, 버퍼에 데이터가 없는데 taken하게되는 오류가 발생할 확률이 매우 높다.
/****** 생산자 ******/
class Producer extends Thread {
Buffer b;
int N;
Producer(Buffer b, int N) {
this.b = b; this.N = N;
}
public void run() {
for (int i=0; i<N; i++)
b.insert(i);
}
}

/****** 소비자 ******/
class Consumer extends Thread {
	Buffer b;
	int N;
		Consumer(Buffer b, int N) {
			this.b = b; this.N = N;
			}

	public void run() {
		int item;
			for (int i=0; i<N; i++)
				item = b.remove();
	}
}

void insert(int item) {
/* check if buf is full */
	while (count == size)
;
/* buf is not full */
	buf[in] = item;
	in = (in+1)%size;
	count++;
}

int remove() {
		/* check if buf is empty */
			while (count == 0)
		;
		/* buf is not empty */
				int item = buf[out];
				out = (out+1)%size;
				count--;
		return item;
		}
}

 

Busy Wait

  • 뮤텍스를 위해 세마포어를 사용하면 상호배재를 해결할 수 있지만 한가지 문제가 있다. 생산자는 삽입을 해야하는데 버퍼가 꽉 찼을 경우, 소비자는 사용해야하는데 버퍼가 비었을 경우, 계속 반복을 돌며 비었는지 안비었는지 확인하고 있다. 이것을 쉬고 있는데도 바쁘다는 의미로 busy wait이라 부른다.
  • 이것은 심각한 cpu낭비를 초래한다. 그러므로 두개의 세마포어를 추가한다. 이번 세마포어는 block을 위한 세마포어이다.

각 단계를 세마포어가 담당한다.

[생산자]
empty.acquire();
	PRODUCE;
full.release();

[소비자]
full.acquire();
	CONSUME;
empty.release();
  • 이렇게 하면 CPU를 효율적으로 사용하면서 상호배타적인 문제도 해결할 수 있다.