CS
[CS] IPC(Inter Process Communication)란?
쌈뽕코딩
2025. 5. 19. 18:49
🤔 IPC란?
컴퓨터 시스템이 점점 복잡해지고 다중 작업(Multitasking)을 수행하게 되면서, 운영체제는 하나의 CPU에서 여러 개의 작업을 동시에 처리하는 구조를 필요로 하게 되었다. 이때 프로세스(Process)라는 개념이 등장한다.
하지만 서로 다른 프로세스를 격리하는 부분에서 "서로 대화를 할 수 없는 문제"가 발생한다.
현실의 시스템에서는 완전히 독립적인 프로세스만 있는 게 아니다. 예를 들어, 웹 서버 프로세스와 데이터베이스 프로세스가 서로 데이터를 주고받아야 하는 상황, 하나의 애플리케이션이 여러 프로세스로 쪼개져 있을 때, 협력하여 일해야하는 상황같이 말이다.
즉, 프로세스는 독립적이지만, 협업이 필요한 경우가 많다. 그런데 서로 메모리에서 격리되어 있으니 "서로 대화 할 수 없는" 상황이 되어버린다. 이런 배경에서 운영체제는 '격리된 프로세스들끼리 안전하게 통신할 수 있는 메커니즘', 즉 IPC를 제공하게 되었다.
🤔 프로세스?
🌟 프로세스는 실행 중인 프로그램이다.
각 프로세스는 자신만의 메모리 공간(코드, 데이터, 힙, 스택 등)을 가지고 있어 다른 프로세스와 메모리를 절대적으로 격리한다.
스레드는 하나의 프로세스 내부에서 생성되며, 프로세스의 메모리 공간(코드, 데이터, 힙)을 공유하므로 IPC가 필요 없다.
다만, 스레드는 동기화(synchronization)가 필요하다(race condition 방지 등).
🤔 격리하는 이유?
보안 - 한 프로세스가 다른 프로세스의 데이터를 건드리면 안 된다.
안정성 - 하나가 죽어도 다른 프로세스에 영향 없어야 한다.
예측 가능성 - 자원을 분리해서 관리해야 스케줄링/관리 용이하다.
🧻 파이프 (Pipe)
한 프로세스의 출력이 다른 프로세스의 입력으로 전달되는 통신 방식
👉 "A가 종이에 적어 관을 통해 B에게 전달"하는 방식
특징
- 단방향 통신 → 한쪽이 쓰고, 다른 쪽이 읽는다.
- 일반 파이프는 부모-자식 프로세스 간 통신에 주로 사용된다.
- 운영체제가 제공하는 버퍼를 통해 데이터를 일시적으로 저장하고 전달한다.
- 리눅스의 | 연산자 (ls | grep)가 대표적 예이다.
예시
# 부모 프로세스가 자식에게 메시지 전달
cat | grep "foo"
- 이 명령어에서 cat은 사용자의 입력을 받고, grep은 그중 "foo"가 포함된 줄만 출력
$ cat | grep "foo"
hello
foobar ← 출력됨
test
foo test ← 출력됨
📎 Named Pipe (FIFO)
mkfifo mypipe # 파이프 파일 생성
echo "hi" > mypipe # 다른 터미널에서 실행
cat < mypipe # 다른 터미널에서 실행
hi
- 일반 파이프의 확장으로, 파일 시스템에 이름을 가진 특별 파일로 생성된다.
- 서로 관련 없는 프로세스들끼리도 통신 가능하며, 양방향 통신도 구현할 수 있다.
📮 메시지 큐 (Message Queue)
커널이 관리하는 메시지를 큐에 저장하고, 필요 시 이를 수신하여 통신
👉 "편지함에 메시지를 넣으면, 다른 프로세스가 꺼내 읽는 방식"
특징
- 운영체제가 제공하는 큐 자료구조를 통해 메시지를 주고받는다. (큐에 여러 메시지를 쌓을 수 있음)
- 각 메시지에는 타입, 길이, 데이터 등의 메타데이터가 포함된다.
- 비동기 통신이 가능하여, 송신자와 수신자가 동시에 존재하지 않아도 된다. → (보내고 나서 기다리지 않아도 됨)
- 커널이 메시지를 관리하므로 보안성과 신뢰성이 높다.
예시
msgsnd(queue_id, &msg, sizeof(msg), 0);
msgrcv(queue_id, &msg, sizeof(msg), 0, 0);
- A 프로세스가 DB 요청 메시지를 큐에 넣고, B 프로세스(DB 서버)가 꺼내서 처리
🧠 공유 메모리 (Shared Memory)
두 개 이상의 프로세스가 동일한 메모리 영역을 공유하여 통신
👉 "같은 칠판을 보며 동시에 쓰고 읽는 방식"
특징
- 속도 매우 빠름 (파일 시스템/커널 경유 없이 메모리 직접 접근)
- 동시에 접근할 경우 데이터가 엉킬 수 있으므로, 동기화 장치(세마포어, 뮤텍스 등)와 함께 사용
- 대용량 데이터 처리에 적합
- 가장 빠른 IPC 방식 (데이터를 복사하지 않고 공유 메모리 영역을 함께 참조하기 때문)
예시
int shmid = shmget(key, size, IPC_CREAT | 0666);
char *data = shmat(shmid, NULL, 0); // attach to shared memory
- shmget(), shmat()으로 메모리 공유
- 데이터를 복사하지 않고 직접 접근
🚥 세마포어 (Semaphore)
공유 자원의 접근을 제어하기 위한 동기화 도구
👉 "지금은 내가 칠판 쓸 차례야!" 하고 깃발 듬
특징
- 자원 접근 제어 (예: 임계 구역 보호)
- 카운터 형태로 접근 가능 여부를 나타냄
- 단독 사용보단 공유 메모리 같은 IPC와 함께 사용
- 실제로 데이터를 전달하진 않고, 공유 자원에 대한 접근 권한을 제어하는 데 사용 (제어용 도구)
유형
- Binary Semaphore - 0과 1만 가지는 신호등 (Mutex처럼)
- Counting Semaphore - 특정 개수 이상의 자원 허용
예시
struct sembuf p = {0, -1, SEM_UNDO}; // P 연산 (잠금)
semop(sem_id, &p, 1);
- semop(), semget() 등을 사용
- 공유 데이터 자체는 없고, 상태(0/1, 숫자)만 관리
- 공유 메모리와 조합해서 사용
☎️ 소켓 (Socket)
네트워크를 통해 다른 프로세스(심지어 다른 컴퓨터의 프로세스)와 통신할 수 있게 해주는 방식
👉 "전화 걸어 직접 대화"
특징
- 원래는 네트워크 통신용으로 개발된 기술이지만, 같은 컴퓨터 내의 프로세스 간 통신에도 사용될 수 있다. - 로컬 통신 (localhost)
- TCP/UDP를 기반으로 하며, 양방향 통신, 멀티 플랫폼, 프로세스 간 거리 제한 없음이라는 장점이 있다.
- 클라이언트-서버 모델을 사용하는 애플리케이션에서 기본적으로 활용된다.
- 가장 일반적이고 유연한 IPC 방식
예시
int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP 소켓 생성
bind(sockfd, ...);
listen(sockfd, ...);
- 웹 브라우저가 localhost의 백엔드 서버와 통신 (HTTP)
🛎️ 시그널 (Signal)
운영체제나 다른 프로세스가 특정 이벤트(인터럽트 등)를 전달하는 수단
👉 "야! 그만해!" 알림만 주기
특징
- 하나의 프로세스가 다른 프로세스에게 이벤트(중단, 재시작 등)를 알리는 메커니즘이다.
- SIGKILL, SIGSTOP, SIGINT 등이 있으며, 비동기적인 통신을 제공한다.
- 프로세스에게 단순히 알림만 전달하며, 실제 데이터는 전달하지 않는다. (예: 종료 요청)
- 처리 루틴을 등록할 수 있으며, 이를 통해 사용자 정의(SIGUSR1) 처리를 수행할 수도 있다.
예시
kill -SIGINT [PID]
trap "echo '종료 시그널 감지됨'" SIGINT
# 실행 후
sleep 100
# 다른 터미널에서 kill -SIGINT [PID]