Computer & Data/Operating System

운영체제) 프로세스간 통신

박스님 2017. 4. 17. 20:18
반응형

▣ IPC ( Interprocess Communication )

● 프로세스간 통신 쟁점

- 프로세스간 정보를 어떻게 전달할 것인가?

- 다수의 프로세스에서 critical activity에서 다른 프로세스를 어떻게 방해하지 않을 것인가?

- 서로 의존성이 있는 경우, 어떤식으로 순서화하는가?

==> 스레드들 간에도 동등한 수준으로 적용



▣ 경쟁 조건 ( Race Conditions)

● 둘 이상의 프로세스가 공유 메모리를 읽고 기록할 때, 마지막 결과는 어느 프로세스가 수행되었는가에 의존한다.

- 해결 : 상호배제 --> 둘 이상의 프로세스가 동시에 공유 데이터의 읽기와 쓰기가 불가능하게 하는 방법




▣ 임계 구역 (Critical Regions)

; 공유 메모리에 접근하는 프로그램 부분

; 어떤 두 프로세스도 동시에 임계 구역에 들 수 없도록 설정

● 상호 배제 (mutual exclusion)

- 어떤 두 프로세스도 동시에 임계 구역 안으로 들어갈 수 없다.

- CPU 속도나 수에 대한 어떤 가정도 없다.

- 임계 구역 밖에서 수행되는 어떤 프로세스도 다른 프로세스를 블록시킬 수 없다.

- 어떤 프로세스도 임계구역에 들어가기 위하여 영원히 기다리지 않는다.




▣  상호 배제 구현 방법 

; 인터럽트 끄기, 락(lock) 변수, 엄격한 교대, Peterson 해법, TLS 명령


● 인터럽트 끄기

- 클록 인터럽트 끔 --> CPU간의 문맥교환이 일어나지 않도록 한다.

- 문제점 : 프로세스가 임계 구역을 떠나면서 인터럽트를 불가능하게 하는 경우,
              CPU가 다수 -> 하나가 인터럽트가 금지되어도 다른 하나는 가능


● 락 (lock) 변수

- 소프트웨어적 해법

- 초기값 0, 들어갈 때 1, 떠날 때 0

- 문제점 : 한 프로세스가 잠금 변수를 1로 set하려는 찰나, 다른 프로세스가 임계 구역에 진입하면?


● 엄격한 교대

- busy waiting

- spin lock : 바쁜 대기를 사용하는 락

- 문제점 : 두 프로세스는 반드시 교대로 수행하여야 한다.



● Peterson 해법

- 엄격한 교대 문제점 해결

#define FALSE	0
#define TRUE	1
#define N		2

int turn;
int interested[N];

void enter_region(int process) {
	int other;

	other = 1 - process;
	interested[process] = TRUE;
	turn = process;
	while (turn == process && interested[other] == TRUE);
}
void leave_region(int process) {
	interested[process] = FALSE;
}   

- 자신의 프로세스 번호를 인자로 제공하며 임계 구역 진입




● TSL (Test and Set Lock ) 명령

- 하드웨어적 해결책

- 몇몇 시스템 명령 ( TSL REGISTER, LOCK )

- 메모리 워드의 LOCK을 읽어 register에 저장 -> LOCK에 0이 아닌 값을 입력

- 워드를 읽고 쓰는 연산은 분할이 불가능.

- TSL 명령을 수행하는 CPU는 수행이 끝날 때까지, 메모리 버스를 잠금 -> 다른 어떤 CPU도 메모리에 접근 불가능

=> 공유 변수 lock을 사용

- lock이 0이면 어떤 프로세스도 TSL을 사용하여 이를 1로 설정 후, 공유 메모리에 읽기와 쓰기를 수행 가능

- 작업후 lock을 다시 0으로 설정






▣  슬립과 깨움 ( Sleep and Wakeup )

● 바쁜 대기 -> 임계 구역 진입이 허용되지 않을 때, CPU 시간을 낭비하는 대신 블록하는 프로세스간 통신 고려

- sleep : 호출자를 block, --> 다른 프로세스가 깨울 때 (wakeup)까지 보류

- wakeup


● 생산자 - 소비자 문제 (한정된 버퍼 문제)

- 생산자 (producer) : 버퍼에 정보를 삽입

- 소비자 (consumer) : 버퍼에서 정보를 제거

- 버퍼가 가득 차 있다면? 생산자를 sleep --> 소비자 수행 후, wakeup

#define N		100
#define TRUE	1
#define FALSE	0
int count = 0;

void producer(void) {
	int item;

	while (TRUE) {
		item = produce_item();
		if (count == N) sleep();
		insert_item(item);
		count = count + 1;
		if (count == 1) wakeup(consumer);
	}
}

void consumer(void) {
	int item;

	while (TRUE) {
		if (count == 0) sleep();
		item = remove_item();
		count = count - 1;
		if (count == N - 1) wakeup(producer);
		consume_item(item);
	}
}

  < 문제점 >

- count에 대한 접근 -> 경쟁 조건

- wakeup signal 분실

  < 해결책 >

- wakeup waiting bit 추가 --> wakeup signal 저장




▣  세마포어 ( Semaphore )

- 생산자 소비자 문제의 근본적 해결을 위함 ( Dijkstra )

- 새로운 공유변수 도입

a. 필수적인 단위 동작

b. down, up 두 개의 연산 제안 ; 원자적 동작( atomic action )

- mutex ; 세마포어 변수의 한 종류 --> 임계구역의 진입여부를 결정 ( 생산자와 소비자가 동시에 버퍼에 접근하지 못하도록 )

  full ; 차있는 슬롯 수

  empty ; 비어 있는 슬롯 수

#define N		100
#define TRUE	1
#define FALSE	0

typedef int semaphore;
semaphore mutex = 1;
semaphore empty = N;
semaphore full = 0;

void producer(void) {
	int item;

	while (TRUE) {
		item = produce_item();
		down(&empty);					// <--	if (count == N) sleep();
		down(&mutex);
		insert_item(item);
		up(&mutex);						// <--	count = count + 1;
		up(&full);						//		if (count == 1) wakeup(consumer);
	}
}

void consumer(void) {
	int item;

	while (TRUE) {
		down(&full);					// <--	if (count == 0) sleep();
		down(&mutex);
		item = remove_item();
		up(&mutex);						// <--	count = count - 1;
		up(&empty);						//		if (count == N - 1) wakeup(producer);
		consume_item(item);
	}
}

- 위 생산자 소비자 문제와 비교하기 count 하나로 표현되던 부분들이 up, down을 이용하여 mutex, empty, full로 표현


● 뮤텍스 (mutexes)

- 세마포어의 count가 없는 간단한 버전

- lock / unlock 중 하나의 상태를 갖는다.



▣  모니터 ( Monitors )

- 특수한 형태의 모듈이나 패키지에서 서로 그룹핑된 프로시저, 변수, 자료구조들의 집합

- 상호배제가 low - level 단에서 지원됨 -> " 단 하나의 프로세스만 한 순간에 모닡터에서 활동할 수 있다. "

● 생산자-소비자 문제 해결

- 조건 변수 wait, signal 도입

- sleep, wakeup과 달리 모니터에서는 자동적으로 상호배제가 됨 

-> wait, signal은 상호배제가 아님 

-> 문맥교환 될 걱정하지않고 연산 완료 가능



▣  메시지 패싱 ( Message Passing )

- send / recive ; 시스템 호출 일종

- acknowledgement 분실 문제 -> 메시지 구별 필요

- 인증 --> 프로세스의 유일성 보장

● 생산자 - 소비자 문제

- 공유 메모리가 아닌, 메시지 전달로 해결

- 가정

a. 모든 메시지는 동일한 크기

b. 메시지는 운영체제에 의해 자동 버퍼링

- 방법

a. 소비자는 시작할 때, N개의 빈 메시지를 생산자에게 보냄

b. 생산자는 소비자에게 전달할 아이템을 생산하면, 빈 메시지 수신 --> 아이템이 들어 있는 메시지 전송

#define N		100
#define TRUE	1
#define FALSE	0
typedef char* message;

void producer(void) {
	int item;
	message m;

	while (TRUE) {
		item = produce_item();
		receive(consumer, &m);
		build_message(&m, item);
		send(consumer, &m);
	}
}

void consumer(void) {
	int item;
	message m;

	for (int i = 0; i < N; i++) send(producer, &m);
	while (TRUE) {
		receive(producer, &m);
		item = extract_item(&m);
		send(producer, &m);
		consume_item(item);
	}
}



▣  장벽 ( Barriers )

; 동기화 매커니즘

● 다음 단계로 진행전 모든 프로세스들이 전부 모일때까지 블록

- ex/응용이 단계별로 구성

->  모든 프로세스가 다같이 다음 단계로 진행할 준비가 되어야만 다음 단계로 진행한다는 규칙이 있는 경우

-> 각 단계의 끝에 장벽 설치

반응형