1. IPC 란?
- 프로세스는 스레드와 다르게 독립적으로 실행된다. 이처럼 독립적인 자원을 가진 프로세스끼리 통신에 사용되는 기법을 IPC 라고 한다.
2. 생산자-소비자 문제(Producer-Consumer Problem)
생산자란 말 그대로 정보를 생산하는 역할, 소비자란 정보를 소비하는 역할이다.
이렇게 들으면 이해가 잘 안가기 때문에 예시를 들어보자면
1. 생산자 : compiler > 어셈블리 코드 생성 // 소비자 : assembler > 어셈블리 코드를 소비하여 기계어 변환
2. 생산자 : 웹 서버 > request시에 웹 페이지 HTML코드 생성 // 소비자 : 브라우저 > HTML코드를 소비해서 화면에 랜더링 함.
이정도가 대표적인 생산자-소비자에 대한 예시가 될 것 같다. 그래서 다시 생산자-소비자 문제로 돌아와보면 생산자-소비자 문제란 생산자가 데이터를 생성하면 소비자가 데이터를 소비하는 형태의 과정에서 발생하는 문제를 말한다. 이제 이 생산자-소비자 문제를 해결하기 위한 방법에 대해 알아보자
생산자-소비자 문제를 해결하기 위한 방법
1. 공유 메모리 (Shared-memory)
Concurrently하게 실행되고 있는 프로세스 두개가 Buffer 라는 공유 메모리(Shared-memory)를 만들어서 생산자와 소비자가 번갈아가며 접근하여 생산자 프로세스가 버퍼를 채우고, 소비자 프로세스가 버퍼에 있는 내용을 소비하는 방법이다. 공유메모리를 사용하는 이유는 각 프로세스는 독립적인 공간(자원)을 할당받기 때문에 서로 다른 프로세스 끼리는 서로의 메모리에 접근을 못한다. 그래서 모든 프로세스가 접근 가능한 Shared-memory라는 공유 메모리를 만들어 사용하는 방법이다. 이 Shared-memory는 O/S가 관리해준다.
생산자 프로세스인 P와 소비자 프로세스 Q사이에서 버퍼가 비어있으면 P프로세스는 채워야하기 때문에 버퍼에 정보를 넣을동안 Q프로세스는 Wait하고 있어야 한다. 반대로 버퍼에 정보가 있으면 Q프로세스가 버퍼의 데이터들을 소비할 동안 P프로세스는 Wait하고 있어야 한다. 코드로 보면 아래와 같다.
#define BUFFER_SIZE 10
typedef struct{
/**/
} item;
item buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
//producer
void produce(item val) {
//버퍼가 다 참
while(((in + 1) % BUFFER_SIZE) == out) {
/*Wait*/
}
buffer[in] = val;
in = (in + 1) % BUFFER_SIZE;
}
//consumer
void consume(item val) {
//버퍼 비어있으면
while(in == out) {
/*Wait*/
}
val = buffer[out];
out = (out + 1) % BUFFER_SIZE;
}
2. 메세지 전달 방법(Message-Passing)
메모리 자체는 공유메모리와 비슷한 개념이지만 이전에 Shared-memory에서는 프로그래머가 직접 관리를 해줘야 했지만 Message Passing 방식에서는 관리부분을 OS가 해주는 방식이다. OS즉 Kernel은 Send(message), receive(message) 두가지의 syscall을 지원해준다.
2-1. Message-Passing System의 종류
1. 직접 전송 방법 : Direct communication
- 직접 전달이기 때문에 누구한테 주는지 명확하기 때문에 Link가 자동적으로 생성된다.
- 위와 같은 이유로 프로세스 간 하나의 Link만 성립한다.
send(P, message) : P한테 message를 보냄
receive(Q, message) : Q로부터 message를 받음
2. Port(Mailbox)를 통한 간접 전달 방법 : Indirect communication
- 한 쌍(생산자-소비자) 프로세스 간 연결은 공유 port(link)를 가질 때만 연결된다.
- port에 대해 여러개의 프로세스들이 접근할 수 있다.
- port를 사용하여 복잡한 링크를 생성할 수 있다.
send(A, message) : A mailbox로 메시지를 보냄
send(A, message) : A mailbox로부터 메시지를 받아옴 > 여러 프로세스가 A mailbox에 접근, 공유가능
2-2. Shared-Memory VS Message-Passing
1.Shared-memory
- User level에 존재하는 shared memory를 생성해서 사용한다.
- 효율은 좋지만 다른 프로세스가 접근하기 때문에 동기화 문제가 발생한다.
2.Message-passing
- Message-queue를 구현하여 사용한다.
- 커널이 개입해서 데이터를 전달하고 큐를 사용하기 때문에 Shared-memory보다 비교적 안전한 방법이다.
- Queue의 push, pop연산으로 인해 오버헤드가 발생하기 때문에 효율이 낮아질 수 있다.
2-3 동기화 방법 (Synchronization)
보낼 데이터 용량 : 2GB, Buffer size : 1GB라고 가정할 때를 예시로 들어서 설명한다.
1. Blocking - Synchronous
- Blocking send : 송신자가 보낸 메시지를 수신자가 수신할 때 까지 송신자를 정지(block)시킨다.
송신자가 버퍼 size만큼 1GB 적재 > 수신자 1GB가져갈 때 까지 송신자 block > 수신자가 가져가면 다시 송신자가 적재
- Blocking receive : 메시지를 다 받을 때 까지 대기.
송신자가 버퍼 size만큼 1GB 적재 > 수신자가 1GB를 받고 Wait 함 > 다시 송신자가 1GB 보내면 > Wait풀고 메시지 수신
1-2 Blocking이 왜 Synchronous?
Blocking : 작업1이 작업2를 호출하고 제어권도 같이 넘김.
Synchronous : 작업1이 끝나야 작업2가 시작됨.
2. Non-blocking - Asynchronous
- Non-blocking send : 송신자는 메시지를 보내고 continue
송신자는 수신자가 받든지 말든지 2GB 보내놓고 자기 할일 함. 이후에는 OS가 알아서 처리하도록 방치
- Non-blocking receive : 수신자는 송신자가 보낸 메시지가 있으면 메시지를 받고 없으면 null을 리턴하고 자기 할일 하다가 메시지가 오면 다시 받음.
송신자가 메시지 1GB 적재 > 수신자가 1GB받음 > 다 받았으면 또 받을게 없으니 수신자는 자기 할일 함 > 이후 송신자가 메시지 보내면 > 돌아와서 다시 수신
2-2 Non-blocking이 왜 Asynchronous?
Non-blocking : 제어권은 넘기지 않고 작업2만 실행
Asynchronous : 작업1과 작업2의 요청한 작업에 대해 순서가 없는 것.
Blocking & Non-blocking과 Synchronous & Asynchronous에 대해 자세히 알고싶으면 이 글을 확인해 보길 바란다.
그림 출처 : https://velog.io/@soyeon207/%EB%8F%99%EA%B8%B0-%EB%B9%84%EB%8F%99%EA%B8%B0-blocking-non-blocking
CS 지식을 공부하고 기록하는 개인 공부 블로그입니다.
내용 중 틀린 부분 피드백 혹은 궁금한 점이 있으면 댓글로 남겨주시면 참고 및 답변 달아드리겠습니다🧐
'Computer Science > 운영체제' 카테고리의 다른 글
[OS/운영체제] Thread / 스레드 (1) | 2023.12.22 |
---|---|
[OS/운영체제] 동기 & 비동기 VS 블로킹 & 논블로킹 (1) | 2023.12.18 |
[운영체제] Memory layout (0) | 2023.12.14 |
[OS/운영체제] 프로세스 / Process (0) | 2023.12.13 |
[운영체제] Interrupt란? (1) | 2023.11.12 |