프로세스 간 통신 (IPC: Inter Process Communication)
프로세스나 쓰레드는 독립적으로 실행된다. 프로세스나 쓰레드가 협업하거나 데이터를 병렬로 처리하기 위해서는 데이터를 주고 받아야하는데, 하나의 프로세스에 속한 쓰레드끼리 데이터를 주고 받는 것은 쉽다. 그러나, 서로 다른 프로세스는 메모리 영역이 다르기에 공유된 메모리를 통하여 통신하는 것이 어렵다.
프로세스 간 통신(Inter Process Communication)은 운영체제가 제공하는 프로세스끼리 쉽게 데이터를 주고 받는 통신 방법이다. 대표적인 프로세스 간 통신의 종류는 다음과 같다.
- 공유 메모리나 공유 파일을 이용한 통신: 가장 기본적인 프로세스 간 통신 방법으로, 일정한 메모리 영역이나 파일을 공유하고 이를 통하여 데이터를 주고 받는다.
- 파이프를 이용한 통신: 하나의 컴퓨터 내에서 프로세스 간 통신에 가장 많이 사용되는 수단이다.
- 소켓을 이용한 통신: 컴퓨터와 컴퓨터가 네트워크로 연결된 경우의 통신에 주로 사용되는 수단이다.
프로세스 간 통신의 분류
프로세스 간 통신은 동시에 실행되는 프로세스끼리 데이터를 주고받는 작업이다.
통신 방향에 따른 분류
통신은 데이터가 전송되는 방향에 따라 양방향 통신, 반양방향 통신, 단방향 통신으로 분류된다.
- 양방향 통신(Duplex Communication): 데이터를 양쪽 방향으로 동시에 전송할 수 있는 구조로, 소켓을 이용한 통신이 이에 해당된다.
- 반양방향 통신(Halfduplex Communication): 데이터를 양쪽 방향으로 전송할 수 있지만, 동시 전송은 불가능하고 특정 시점에 한 방향으로만 전송할 수 있는 구조이다.
- 단방향 통신(Simple Communication): 한쪽 방향으로만 데이터를 전송할 수 있는 구조로, 공유 메모리나 공유 파일을 이용한 통신, 파이프를 이용한 통신이 이에 해당된다.
통신 구현 방식에 따른 분류
공유 메모리를 사용하는 통신 방식에서, 데이터를 받는 쪽에서는 상대방이 데이터를 언제 보내는지 알 수 없다. 따라서 데이터를 받는 쪽에서는 상태 변화를 살펴보기 위해 반복문을 무한히 실행하며 공유 메모리를 점검해야 한다. 이를 "바쁜 대기(Busy Waiting)"라고 한다. 이와 같은 바쁜 대기는 시스템 차원에서 자원 낭비가 커지게 된다.
이를 해결하기 위해 데이터가 도착했음을 알려주는 "동기화(Synchronization)"을 사용한다. 프로세스 간 통신은 동기화 기능의 유무에 따라 대기가 있는 통신(동기화 통신)과 대기가 없는 통신(비동기화 통신)으로 분류한다.
- 대기가 있는 통신(Blocking Communication): 동기화를 지원하는 방식으로, 데이터를 받는 쪽은 데이터가 도착할 때까지 자동으로 대기 상태에 머무르게 된다. 파이프를 이용한 통신과 소켓을 이용한 통신은 대기가 있는 통신이다.
- 대기가 없는 통신(Non-Blocking Communication): 동기화를 지원하지 않는 방식으로, 데이터를 받는 쪽은 바쁜 대기를 사용하여 데이터가 도착했는지 여부를 직접 확인한다. 공유 메모리나 공유 파일을 이용한 통신은 대기가 없는 통신이다.
프로세스 간 통신의 종류
파일을 이용한 통신
파일 입출력 코드는 파일 열기(open), 파일 쓰기 또는 읽기(write&read), 파일 닫기(close)로 이루어진다.
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
int fd;
char buf[5];
fd = open("com.txt", 0_RDWR);
write(fd, "Test", 5); // 하드디스크로 쓰기
read(fd, buf, 5); // 하드디스크에서 읽기
close(fd);
exit(0);
}
파일 열기 과정에서는 open() 함수를 이용하여 사용하고자 하는 파일이 있는지와 그 파일에 대한 쓰기 권한이 있는지 확인한다. 그 후 파일을 정상적으로 사용할 수 있다면 open() 함수는 해당 파일에 접근할 수 있는 권한인 fd(File Descriptor)를 반환한다.
파일 쓰기 및 읽기 과정에서는 반드시 해당 파일에 대한 접근 권한인 fd를 사용해야 한다.
- write(fd, "Test", 5): com.txt 파일에 Test라는 문자열을 쓰라는 것이다. 뒤의 5는 Test의 크기가 5B이기에 문자열의 크기를 명시한다. (문자열의 끝인 null값도 포함하여 5B가 된다.)
- read(fd, buf, 5): com.txt 파일에서 5B를 읽어 변수 buf에 저장하라는 것이다.
파일 닫기 과정에서는 close() 함수를 이용하여 파일을 닫는다.
파일을 이용한 통신은 부모-자식 관계의 프로세스 간 통신에 많이 사용된다. 운영체제가 프로세스 동기화를 지원하지 않기에 프로세스가 알아서 동기화해야한다. 부모 프로세스가 wait() 함수를 이용하여 자식 프로세스의 작업이 끝나기를 기다렸다가 작업을 시작한다.
파이프를 이용한 통신
파이프를 이용한 통신도 open() 함수로 기술자를 얻어 작업한 후, close() 함수로 마무리한다. 단방향 통신 방법이며 파이프를 이용하여 양방향 통신을 하려면 파이프 2개를 사용해야 한다. 파이프는 이름 없는 파이프와 이름 있는 파이프로 분류된다.
- 이름 없는 파이프(Anonyous Pipe): 일반적인 파이프의 형태이며, 부모-자식 프로세스와 같이 서로 관련 있는 프로세스 간 통신에 주로 사용된다.
- 이름 있는 파이프(Named Pipe): FIFO라고 불리는 특수 파일을 이용하며 서로 관련 없는 프로세스 간 통신에 주로 사용된다.
소켓을 이용한 통신
하나의 컴퓨터에 있는 프로세스 간 통신 뿐만 아니라 여러 컴퓨터에 있는 프로세스끼리도 통신이 가능하다. 이를 네트워킹이라고 하며, 소켓을 이용한 통신이 사용된다. 소켓은 프로세스 동기화를 지원하기에 데이터를 받는 쪽의 프로세스가 바쁜 대기를 하지 않아도 되며 소켓 1개로 양방향 통신이 가능하다.
다른 컴퓨터의 프로세스와 통신하기 위해서는 그 컴퓨터의 위치를 파악하고 원격지의 시스템 내 여러 프로세스 중 어떤 것과 통신할지 결정해야 한다. 통신하려는 프로세스가 소켓에 쓰기 연산을 하면 데이터가 전송되고, 읽기 연산을 하면 데이터를 수신한다.