호우동의 개발일지

Today :

article thumbnail

프로세스 간 통신

  • 운영체제 내에서 실행되는 병행 프로세스들은 독립적이거나 협력적인 프로세스 일 수 있다.
    • 독립적 : 실행 중인 다른 프로세스들과 데이터를 공유하지 않는 프로세스
    • 협력적 : 실행 중인 다른 프로세스들과 영향을 주고받는 프로세스

 

 

 

프로세스 협력을 허용하는 환경을 제공하는 이유

  • 정보 공유
    • 여러 응용 프로그램이 동일한 정보(복사, 붙여 넣기 등)를 원할수도 있음
      → 그러한 정보를 병행적으로 접근할 수 있는 환경을 제공해야 함

  • 계산 가속화
    • 특정 태스크를 빨리 실행하고자 함
      → 태스크를 서브태스크로 나누어 이를 다른 서브태스크들과 병렬로 실행하면 됨
    • 가속화는 복수 개의 처리 코어를 가진 경우에만 가능

  • 모듈성
    • 시스템 기능을 별도의 프로세스 또는 스레드로 나누어, 모듈식 형태로 시스템을 구성할 수도 있음

 

 

 

 

 

프로세스 간 통신 기법

  • 협력적 프로세스들이 서로 데이터를 주고받을 수 있는 기법(IPC)
    • 기본적으로 통신 간에는 두 가지 모델이 존재 → 공유 메모리 모델, 메시지 전달 모델

  • 공유 메모리 모델
    공유 메모리 모델
    공유 메모리 모델
    • 공유 메모리 영역은 협력 프로세들에 의해 공유되는 메모리의 영역
    • 공유 메모리 영역에 데이터를 읽고 쓰고 함으로써 정보를 교환
    • 메시지 전달 모델보다 빠름 ( 시스템 콜을 덜 사용 )
      • 공유 메모리 영역이 구축되면 커널의 도움이 필요 없음


  • 메시지 전달 모델
    메시지 전달 모델
    메시지 전달 모델

    • 통신이 협력 프로세스들 사이에 교환되는 메시지 전달을 통해 이루어짐
    • 충돌을 회피할 필요가 없기에 적은 양의 데이터를 교환하는데 유용
    • 분산 시스템에서 공유 메모리보다 구현하기 쉽다.

 

 

 

공유 메모리 시스템에서의 프로세스 간 통신

  • 공유 메모리 통신을 하기 위해서는, 통신하는 프로세스들이 공유 메모리 영역을 구축해야 한다.


  • 공유 메모리 영역은 공유 메모리 세그먼트를 생성하는 프로세스의 주소 공간에 위치
    • 공유 메모리 세그먼트를 통해 다른 프로세스들은 이 세그먼트를 자신의 주소 공간에 추가해야 함

  • 운영체제는 일반적으로 한 프로세스가 다른 프로세스의 메모리에 접근하는 것을 금지시킴
    → 공유 메모리는 둘 이상의 프로세스가 해당 제약 조건을 제거하는 것에 동의하는 것
    • 이후, 프로세스들은 공유 영역에 읽고 씀으로써 정보를 교환

  • 운영체제는 책임을 지지 않으며, 모두 프로세스의 책임 → 동시에 동일 위치에 쓰지 않도록 조심
    • 데이터의 형식과 위치는 프로세스에 의해 결정 → 운영체제의 권한이 아님

 

 

 

 

 

협력하는 프로세스의 개념 : 생산자-소비자 문제

  • 생산자 프로세스 → 정보를 생산하는 프로세스
    • 예 : 일반적으로 서버, 웹 콘텐츠를 생산(제공)

  • 소비자 프로세스 → 정보를 소비하는 프로세스
    • 예 : 일반적으로 클라이언트, 자원들을 소비(읽는다).

  • 생산자-소비자 문제 해결책 중 하나 → 공유 메모리 사용
    • 생산자와 소비자 프로세스가 병행되기 위해 필요한 것

      • 생산자가 정보를 채워 넣고, 소비자가 쓰고자 하는 자원의 버퍼가 사용 가능해야 함
      • 쓰고자 하는 자원은 공유하는 메모리 영역에 존재하게 됨
      • 생산자가 한 항목을 생산하고, 그동안 소비자는 다른 항목을 소비 가능
      • 생산자와 소비자가 반드시 동기화되어야 한다.
        ← 생산되지도 않은 항목들을 소비자가 사용할 위험을 막기 위해

    • 2가지 유형의 버퍼 사용 → 무한 버퍼, 유한 버퍼
      • 무한 버퍼
        • 생산자 문제에서는 버퍼의 크기에 실질적인 한계가 없음
        • 소비자는 새로운 항목을 기다려야 하지만, 생산자는 항상 새로운 항목을 만들 수 있음

      • 유한 버퍼
        • 버퍼의 크기가 고정되어 있다.
        • 모든 버퍼가 채워져 있으면 생산자는 기다려야 함
        • 버퍼가 비어있으면 소비자는 기다려야 함

 

 

 

 

 

유한 버퍼가 공유 메모리를 사용해 프로세스 간 통신을 하는 과정

  • 변수 설정
#define BUFFER_SIZE 10 // 담을 수 있는 자원(버퍼) 개수

typedef struct{
    // 자원
} item;

item buffer[BUFFER_SIZE];
int in = 0; // 마지막에 넣은 자원(버퍼) + 1 위치
int out = 0; // 첫 자원(버퍼) 위치
- 공유 버퍼는 2개의 논리 포인터(in, out)을 갖는 원형 배열로 구현
- 변수 in : 버퍼 내에 비어있는 다음 위치를 가리킴
- 변수 out : 버퍼 내에 첫번째로 채워져 있는 위치
- in == out → 버퍼가 비어있음
- (in+1)%BUFFER_SIZE == out → 버퍼가 가득 참
- 해당 방식으로는 BUFFER_SIZE - 1 개까지 채울 수 있음

 

 

 

  • 공유 메모리를 사용하는 생산자 프로세스
item next_produced;
while(true){
    /* 자원을 생산하여 next_produced 변수에 넣음*/

    // 버퍼가 가득 차면 생산을 못하도록 무한 루프
    while(((in+1)% BUFFER_SIZE) == out);

    buffer[in] = next_produced;
    in = (in+1)%BUFFER_SIZE;
}
- 버퍼가 가득차면 생산하지 못하도록 무한 루프
- 그렇지 않으면 in을 하나씩 올려가며 생산한 next_produced를 버퍼에 넣음

 

 

  • 공유 메모리를 사용하는 소비자 프로세스
item next_consumed;

while(true){
    // 버퍼가 비었으면 더이상 못가져오도록 무한 반복
    while(in == out);

    next_consumed = buffer[out];
    out = (out+1)%BUFFER_SIZE;

    /* next_consumed 변수에 다음에 가져올 자원을 담음*/
}
- 버퍼가 비어있으면 소비하지 못하도록 무한 루프
- 그렇지 않으면 out을 하나씩 올려가며 버퍼에서 자원을 가져옴

 

 

 

 

메시지 전달 시스템에서의 프로세스 간 통신

  • 운영체제가 메시지 전달 설비를 통해 협력 프로세스 간의 통신 수단을 제공해 주는 방법
  • 해당 방식은 공유 주소 공간 없이도 프로세스들이 통신 및 동기화를 허용하는 기법 제공
  • 통신하는 프로세스들이 네트워크에 의해 연결된 다른 컴퓨터들에 존재할 수 있는 분산환경에서 유용
    • 예 : 월드 와이드 웹에 사용되는 chat 프로그램에서 사용되는 메시지 전달 통신

  • 메시지 전달 시스템은 최소 두 가지 연산을 제공 → send(message), receive(message)

  • 프로세스가 보낸 메시지는 고정 길이 일수도, 가변 길이 일수도 있다.

    • 고정 길이일 경우 → 시스템 수준의 구현은 직선적, 프로그래밍 작업은 더 힘듦
    • 가변 길이일 경우 → 복잡한 시스템 수준의 구현, 프로그래밍 작업은 간단해짐

  • 두 프로세스가 통신을 하려면 반드시 통신 연결이 설정되어야 한다.
    • 다양한 구현 방법(send() / receive() 논리적인 구현 방법)
      • 직접 또는 간접 통신
      • 동기식 또는 비동기식 통신
      • 자동 또는 명시적 버퍼링

 

 

 

 

 

명명(Naming)

  • 통신을 원하는 프로세스들은 서로를 가리킬 방법이 있어야 함
    → 이를 간접/직접 통신에 사용 가능


  • 직접 통신의 경우
    • 통신하는 프로세스는 수신자 또는 송신자의 이름을 명시해야 함
      • send(P, message) : 프로세스 P에 메시지를 전송한다.
      • receive(Q, message) : 프로세스 Q로부터 메시지를 수신한다.


    • 해당 기법에서의 통신 연결 특성
      • 통신을 원하는 각 프로세스의 쌍들 사이에 연결이 자동으로 구축된다.
      • 프로세스들은 통신을 위해 상대방의 신원(identity)만 알면 됨
      • 연결은 정확히 두 프로세스 사이에만 연관됨
      • 통신하는 프로세스들의 각 쌍 사이에는 정확하게 하나의 연결만 존재해야 한다.

    • 해당 방식은 주소 방식에서 대칭성 → 송/수신자 프로세스 모두 상대방의 이름을 제시해야 함
      • 해당 기법의 변형 → 비대칭으로 사용
        • 송신자만 수신자 이름을 지명
          • send(P, message) : 메시지를 프로세스 P에 전송

          • receive(id, message) : 임의의 프로세스로부터 메시지를 수신
            • 변수 id는 통신을 발생시킨 프로세스의 이름으로 설정됨


    • 단점
      • 대칭/비대칭 기법은 모두 프로세스를 지정하는 방식 때문에 모듈성을 제한
      • 프로세스의 이름을 바꾸면 다른 모든 프로세스 지정 부분을 검사해야 함(하드 코딩 방식)


  • 간접 통신의 경우
    • 메시지들이 메일박스 또는 포트로 송신되고, 그것으로부터 수신됨
      • 메일박스(mail box) : 프로세스들에 의해 메시지들이 추가/제거될 수 있는 객체
        • 각 메일 박스는 고유의 id를 가짐

    • 프로세스는 다수의 상이한 메일박스를 통해 다른 프로세스들과 통신
      • 두 프로세스들이 공유 메일박스를 가질 때만 이들 프로세스가 통신 가능
      • send(A, message) : 메시지를 메일박스 A로 송신한다.
      • receive(A, message) : 메시지를 메일박스 A로부터 수신한다.

    • 간접 통신 연결의 성질
      • 한 쌍의 프로세스들 사이의 연결은 이들 프로세스가 공유 메일박스를 가질 때만 구축
      • 연결은 두 개 이상의 프로세스들이 연관될 수 있다.
      • 통신하고 있는 각 프로세스 사이에는 다수의 서로 다른 연결이 존재할 수 있고,
        각 연결은 하나의 메일박스에 대응된다.

        • 다수의 프로세스가 동시에 메시지를 수신할 때 어느 프로세스가 받는가?
          • 선택한 기법에 좌우됨
            1. 하나의 링크는 최대 두 개의 프로세스와 연관되도록 허용
            2. 한순간에 최대 하나의 프로세스가 receive() 연산이 실행되도록 허용
            3. 어느 프로세스가 수신할 것인지 시스템이 임의로 결정(알고리즘에 의해)
              • 시스템은 송신자에게 수신자를 알려줄 수 있다.

    • 메일 박스는 한 프로세스 또는 운영체제에 의해 소유될 수 있음
      • 메일 박스가 한 프로세스에게 소유될 경우 → 메일 박스가 프로세스의 주소 공간의 일부다.
        • 메일 박스의 소유자와 사용자를 구분할 수 있음
          • 메일 박스의 소유자 → 메일 박스로부터 메시지를 수신만 가능한 프로세스
          • 메일 박스의 사용자 → 메일 박스로부터 메시지를 송신만 가능한 프로세스

        • 메일박스로 보내진 메시지를 어느 프로세스가 수신받았는지 정확히 알 수 있음
        • 메일 박스를 소유하고 프로세스가 종료할 때 메일 박스는 사라짐
          → 메일 박스 사용자 프로세스는 이 사실을 무조건 통보받아야 함

      • 운영체제가 소유한 메일박스(자체적으로 존재함)
        • 독립적인 것으로 어떤 프로세스에 포함되지 않음
        • 운영체제는 한 프로세스에 다음을 할 수 있도록 허용하는 기법을 제공해야 함
          • 새로운 메일 박스를 생성한다.
            • 새로운 메일박스를 생성하는 프로세스는 기본으로 메일 박스의 소유자가 됨
              → 초기에는, 소유자만이 메일박스를 통해 메시지를 수신받을 수 있음
          • 메일박스를 통해 메시지를 송/수신한다.
          • 메일박스를 삭제한다.

 

 

 

 

동기화(Synchronization)

  • 프로세스 간의 통신은 send와 receive 프리미티브에 대한 호출에 의해 발생
    • 각 프리미티브를 구현하기 위한 서로 다른 설계 옵션이 존재
      → 메시지 전달 방식의 차이(봉쇄형 - 동기식, 비봉쇄형 - 비동기식)

      • 봉쇄형 보내기 : 송신 프로세스는 메시지가 수신될 때까지 봉쇄
      • 비봉쇄형 보내기 : 송신 프로세스가 메시지를 보내고 작업을 재시작
      • 봉쇄형 받기 : 메시지가 이용 가능할 때까지 수신 프로세스가 봉쇄됨
      • 비봉쇄형 받기 : 송신하는 프로세스가 유효한 메시지 또는 null을 받는다.

  • send()와 receive()가 모두 봉쇄형(랑데부) 일 때, 생산자 소비자 문제는 쉽게 해결
    • 생산자는 봉쇄형 send()를 호출하고 메시지가 수신자 또는 메일 박스가 전달될 때까지 기다림
    • 소비자는 봉쇄형 receive()를 호출하면 메시지가 전달될 때까지 봉쇄됨

 

 

 

 

버퍼링(Buffering)

  • 통신하는 프로세스들에 의해 교환되는 메시지는 임시 큐에 들어 있다.
  • 큐를 구현하는 방식
    • 무용량(zero capacity)
      • 큐의 최대 길이가 0 → 링크 자체 안에 대기하는 메시지를 가질 수 없음
      • 송신자는 수신자가 메시지를 수신할 때까지 기다려야 함
      • 때때로 버퍼가 없는 메시지 시스템이라고 불림

    • 유한 용량(bounded capacity)
      • 큐는 유한한 길이 n을 가짐
      • 큐가 가득 차지 않으면 송신자는 대기하지 않고 실행을 계속한다.
      • 큐가 가득 차면 송신자는 큐 안에 공간이 이용 가능해질 때까지 봉쇄한다.
      • 자동 버퍼링이라고도 불림

    • 무한 용량(unbounded capacity)
      • 큐는 잠재적으로 무한한 길이를 가진다.
        → 메시지들이 얼마든지 큐 안에서 대기 가능
      • 송신자는 절대 봉쇄하지 않는다.
      • 자동 버퍼링이라고도 불림