Search
Duplicate
👩🏻‍💻

[운영체제] 프로세스간 통신(IPC)

간단소개
프로세스간 통신에는 어떤 방법이 있는지 알아보자!
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
Operating System
운영체제
Scrap
태그
9 more properties
이번 포스팅 그림 요약—
프로세스의 실행 - 독립적 실행 / 협력적 실행
—> 독립적 실행인경우 CPU의 타임 스케쥴링만 잘 해주면 문제 없음.
협력적 실행이 필요한 경우가 있음.
독립적 실행 → 공유하는 데이터도 없고 메세지 주고받을 사항이 없는 경우.
협력적 실행 → 영향을 주거나 받는 경우 ⇒ 데이터를 공유하거나 메세지를 주고 받는 경우
IPC (Inter_process Communication)
데이터를 주거나 받거나 하는 경우.
→ 공유 메모리를 써서 데이터를 주고 받는 방법
→메세지를 주고 받는 방법 중
한가지로 통신을 하면 된다.
공유 메모리 방법 : 예를 들어, Process A(아빠)와 Process B(아들) 사이에 shared memory(용돈함)이 있어서, 아빠가 용돈을 넣으면 아들이 가져가는 구조.
메세지 주고 받는 방법(메세지 파싱) : 운영체제에서 맡긴다.
아빠가 은행 계좌에 입금을 하면, 은행(운영체제)이 알아서 아들 계좌에다가 송금.
Producer-Consumer Problem (생산자 - 소비자 문제)
협력하는 프로세스들 간에 생기는 가장 기본적인 통신 문제.
생산자 - 정보를 생산
소비자 - 정보를 소비
하는 모델
ex > webserver - browser
브라우저가 리퀘스트하면 웹 서버가 html 파일을 전송
1.
공유메모리를 사용한 솔루션
생산자와 소비자는 concurrently하게 돌아간다.(각자 자기 할 일을 한다)
버퍼를 만들어서, 생산자는 버퍼를 채우고, 소비자는 버퍼를 비운(소비한)다.
이때, bounded buffer인 경우가 일반적인데, buffer가 가득차면 생산자는 wait 하고 있어야 한다. buffer가 비워져 있는 경우 소비자는 wait해야한다.
이 버퍼를 shared memory(생산자와 소비자가 공유하고 있는 영역)로 만든다.
각각 프로세스의 영역은 서로 침범할 수 없다.(침범시 문제가 됨)
따라서 두 프로세스 모두 접근 가능한 shared memory는 OS가 특별히 관리해줘야 한다.
구조체를 만들어서 shared buffer를 하나 만들었다고 치면, 생산자는 in을 증가 시키고, 소비자는 out을 증가 시키면서 데이터를 생산하고 소비하는 식으로 구현 할 수 있다.
생산자는 item을 하나 만들어서 buffer에 채운다.
in + 1 == out이면 (buffer가 가득차면) 대기한다.(do_nothing)
비어있다면 버퍼를 채운다.
소비자는 버퍼에 있는 item가져와서 소비
버퍼를 통해서 동기화가 잘 이루어 진다.
→ 문제점 : 메모리 영역을 공유하게 되면, 메모리 영역에 명시적으로 프로그래머가 짜야한다. 생산자와 소비자가 각 1개씩만 있을 때는 문제가 되지 않지만, 생산자가 n개가 되거나 소비자가 n개가 되었는데 shared memory는 1개인 경우 사람이 직접 다 프로그래밍 해주어야한다.
2.
메세지 파싱을 이용한 솔루션
쉐어드 메모리에서 복잡해지는 문제점은 OS가 알아서 해결해준다.
OS가 “서로 메세지를 주고받는 프로세스들”에게 api(수단)를 제공한다.—> 메세지를 주고 받는 것을 편하게 할 수 있게 한다.
생산자는 메세지를 보내기만 한다.
소비자는 메세지를 받기만 한다.
나머지는 운영체제에서 다 알아서 해준다.
⇒ 메세지 패싱 방법에서는 수많은 prosumer들이 통신을 할 때 문제가 될 수 있어서 따로 shared memory가 필요해질 수도 있다. → 후에 다시 다룰 것.
메세지 패싱 방법에서는 프로그래머 입장에서는 생산자가 소비자에게 다이렉트로 메세지를 보내는 것.(중간 모든 과정은 OS의 system call 안에서 이루어짐) 우리 입장에서는 생산자(P)와 소비자(Q)를 direct로 연결해주는 Communication Link만 만들어주면 된다.
send() / receive() 두개의 시스템 콜만 적용을 하면 된다.
communication link의 구현 방법도 나름 다양해 진다.
→direct / indirect → 직접 / 간접
→synchronous / asynchronous
1만원 이하시 5만원 / 아무때나(기분 좋으면) 용돈 주는 모델
→automatic / 명시적 버퍼링
다이렉트하게 보낼 시 → 받는 사람을 명시적으로 정해서 주는 방식. ex > send(P, message) , receive(Q, message) → 어떤 프로세스가 받을 지를 명시해야한다.
⇒ 이경우 커뮤니케이션 링크는 자동적으로 생성된다.
⇒ 이 링크는 두 프로세스간에서는 단 하나만 존재한다.
indirect하게 보낼시 →(ex 용돈함) 메세지는 메일박스(mailbox or ports)로 전송하고, 메일박스에서 수신 할 수 있다. ⇒ 운영체제에서 요즘은 port라고 많이 부른다. 이 포트를 사용함으로써, send(A, message) , receive(A, message) → 포트A에게 메세지를 주기만 하고, 포트 A에서부터 메세지를 수신한다(읽어온다).
⇒2개의 프로세스가 포트를 공유할 때 비로소 링크가 생성된다.
⇒하나의 링크가 여러개의 프로세스들이 커뮤니케이션 하는데 사용해도 문제 되지 않는다.
⇒여러개의 differnet link들이 존재할 수 있다. (복잡한 커뮤니케이션 링크도 만들 수 있다.)
→OS 입장에서는 indrect한 통신이 가능하게 하려면 사용자가
메일박스(포트)를 만들고
메일박스(포트)를 통해 메세지들을 주고 받고
메일박스(포트)를 삭제
할 수 있게 해주면 된다.
포트?(port? == mailbox(좀 옛날 용어 느낌)
하나의 object인데,
이 오브젝트에게 프로세스가 메세지를 보낼 수 있고,
이 오브젝트로 부터 메세지가 삭제(소비, 수신) 될 수 있다.
단, 이런 프로세스간의 통신을 실제로 구현하기 시작하면,
좀 더 고려해야하는 사항들이 생긴다.
blocking io / non-blocking io
(= synchronous io / asynchronous io)
예를 들어, mailbox(포트 = 버퍼)의 크기가 1G인데, 센더가 2G짜리 영화를 메일박스에 보냈다고 하자.
blocking send : 소비자가 메일 박스를 소비해서 남은 데이터를 모두 전송할 수 있을 때 까지 기다린다(센더가 blocked된다)
non-blocking send : 센더는 운영체제에게 send(2G) 명령만 내리고(요청만 보내고) 계속 할 일 을 하고, 버퍼보다 큰 용량의 데이터를 보내는 일에 대한건 운영체제가 모두 처리해 준다.
blocking receive : 리시버가 센더가 메일박스를 채울때까지 기다린다.
Non-blocking receive : 리시버가 valid message를 받으면 무조건 리턴을 하거나 , 없다면 null messagef를 리턴한다.
blocking send / receive를 쓴다 (synchronous io)
⇒ 동기화 된다.
센더가 상대(소비자 프로세스==리시버)가 전송을 다 받았다는 것을 확신 할 수 있으므로 요금 부과 시점이 명확하다.
but 센더가 모든 데이터를 다 보낼때까지 기다려야하므로 프로세스의 실행 속도가 느리다.
non-blocking send / receive를 쓴다 (asynchronous io)
⇒비 동기적 전송
센더가 상대(리시버)가 전송을 다 받았다는 것을 확신 할 수가 없다.(운영체제가 다 보냈겠거니 하고 센더는 다른일을 하기 때문) 요금 부과 시점이 불 명확하다.
but 센더는 운영체제에게 send 요청만 보내고 다른 일을 할 수 있기에, 센더나 리시버 프로세스 입장에서는 효율적으로, 빠른 속도로 실행 될 수 있다.