[IPC] Shared Memory - 가장 빠른 프로세스 간 통신

2026. 2. 27. 16:03·Dev/System Programming

들어가며

지난 글에서 FIFO (Named Pipe)를 다뤘는데, 실습하면서 한 가지 아쉬운 점이 있었습니다. 바로 속도였죠. 간단한 메시지 주고받기에는 충분했지만, 큰 데이터를 전송하려니 느렸습니다.

왜 느릴까요? FIFO는 Kernel을 거쳐서 데이터를 복사하기 때문입니다.

FIFO 방식:
Writer → [User Space]
       ↓ (복사!)
     [Kernel Space]
       ↓ (또 복사!)
     [User Space] → Reader

→ 2번 복사! 느림!

"메모리를 그냥 공유하면 안 되나?" 라는 생각이 들었습니다. 그게 바로 오늘 다룰 Shared Memory (공유 메모리)입니다.

Shared Memory란?

개념

Shared Memory는 여러 프로세스가 같은 메모리 영역을 공유하는 IPC 방식입니다. 복사 없이 직접 접근하기 때문에 IPC 중 가장 빠릅니다.

Shared Memory 방식:
Process A ──→ [Shared Memory] ←── Process B
             (공유된 메모리)

→ 복사 없음! 빠름!

성능 비교 (1MB 데이터 전송)

직접 벤치마크를 돌려봤습니다:

FIFO:            8.5 ms
Shared Memory:   0.8 ms

→ 약 10배 차이

FIFO vs Shared Memory

특징 FIFO Shared Memory
속도 보통 (~8ms) 매우 빠름 (~0.8ms)
복사 2번 (User→Kernel→User) 0번
동기화 자동 (Kernel이 처리) 수동 (Semaphore 필요)
사용 난이도 쉬움 중간
데이터 크기 작은 메시지 큰 데이터

 

언제 뭘 쓸까?

  • 간단한 통신 → FIFO
  • 대용량 데이터 → Shared Memory
  • 실시간 성능 중요 → Shared Memory

실전: Shared Memory 구현

이론은 여기까지! 직접 만들어 봅시다.

POSIX vs System V

Shared Memory에는 두 가지 API가 있습니다:

System V: 오래된 방식 (shmget, shmat)
POSIX:    최신 방식 (shm_open, mmap)

→ POSIX를 사용합니다 (더 깔끔함)

1단계: Shared Memory 생성

#include <sys/mman.h>
#include <fcntl.h>

#define SHM_NAME "/my_shm"
#define SHM_SIZE 4096

int main(void)
{
    // 1. Shared Memory 객체 생성
    int fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);
    if (fd == -1) {
        perror("shm_open");
        exit(1);
    }

    // 2. 크기 설정
    ftruncate(fd, SHM_SIZE);

    // 3. 메모리 매핑
    void *ptr = mmap(NULL, SHM_SIZE, 
                     PROT_READ | PROT_WRITE,
                     MAP_SHARED, fd, 0);

    if (ptr == MAP_FAILED) {
        perror("mmap");
        exit(1);
    }

    printf("Shared Memory created!\n");
    printf("Address: %p\n", ptr);

    // 이제 ptr을 일반 메모리처럼 사용!
    strcpy(ptr, "Hello, Shared Memory!");

    return 0;
}

2단계: Writer 프로그램

// shm_writer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

#define SHM_NAME "/chat_shm"
#define SHM_SIZE 4096

int main(void)
{
    // SHM 생성
    int fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);
    ftruncate(fd, SHM_SIZE);

    // 메모리 매핑
    char *ptr = mmap(NULL, SHM_SIZE, 
                     PROT_READ | PROT_WRITE,
                     MAP_SHARED, fd, 0);

    printf("=== Writer ===\n");
    printf("Enter messages (type 'quit' to exit):\n");

    while (1) {
        printf("You: ");
        fgets(ptr, SHM_SIZE, stdin);

        if (strncmp(ptr, "quit", 4) == 0)
            break;

        printf("Written to shared memory!\n");
        sleep(1);  // Reader가 읽을 시간
    }

    // 정리
    munmap(ptr, SHM_SIZE);
    close(fd);
    shm_unlink(SHM_NAME);

    return 0;
}

3단계: Reader 프로그램

// shm_reader.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

#define SHM_NAME "/chat_shm"
#define SHM_SIZE 4096

int main(void)
{
    // SHM 열기
    int fd = shm_open(SHM_NAME, O_RDONLY, 0666);
    if (fd == -1) {
        perror("shm_open");
        exit(1);
    }

    // 메모리 매핑
    char *ptr = mmap(NULL, SHM_SIZE,
                     PROT_READ,
                     MAP_SHARED, fd, 0);

    printf("=== Reader ===\n");
    printf("Reading from shared memory...\n");

    char prev[SHM_SIZE] = {0};

    while (1) {
        // 내용이 바뀌었으면 출력
        if (strcmp(ptr, prev) != 0) {
            printf("Received: %s", ptr);
            strcpy(prev, ptr);

            if (strncmp(ptr, "quit", 4) == 0)
                break;
        }

        usleep(100000);  // 100ms마다 체크
    }

    // 정리
    munmap(ptr, SHM_SIZE);
    close(fd);

    return 0;
}

컴파일 & 실행

# 컴파일 (중요: -lrt 옵션!)
$ gcc shm_writer.c -o writer -lrt
$ gcc shm_reader.c -o reader -lrt

# 터미널 1
$ ./reader
=== Reader ===
Reading from shared memory...

# 터미널 2
$ ./writer
=== Writer ===
Enter messages:
You: Hello!
Written to shared memory!

# 터미널 1 출력
Received: Hello!

함정: 동기화 문제

처음 실행했을 때 이상한 현상이 발생했습니다.

Writer: "Hello World!"
Reader: "Hello Wor"
Reader: "Hello World!"
Reader: "Hello World!!@#$%"  ← 쓰레기 값!

문제: Writer가 쓰는 도중에 Reader가 읽음!

Race Condition

T0: Writer: ptr[0] = 'H'
T1: Writer: ptr[1] = 'e'
T2: Reader: 읽기! → "He" (불완전!)
T3: Writer: ptr[2] = 'l'
...

이게 바로 Race Condition입니다. FIFO는 Kernel이 알아서 처리해줬는데, Shared Memory는 우리가 직접 처리해야 합니다!

해결책: Semaphore

Semaphore로 동기화를 구현합니다.

#include <semaphore.h>

sem_t *sem;

// Writer
sem = sem_open("/my_sem", O_CREAT, 0666, 1);

sem_wait(sem);      // Lock
strcpy(ptr, msg);   // 쓰기
sem_post(sem);      // Unlock

// Reader
sem_wait(sem);      // Lock
strcpy(buf, ptr);   // 읽기
sem_post(sem);      // Unlock

완전한 코드:

// shm_writer_sync.c
int main(void)
{
    int fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);
    ftruncate(fd, SHM_SIZE);
    char *ptr = mmap(NULL, SHM_SIZE, 
                     PROT_READ | PROT_WRITE,
                     MAP_SHARED, fd, 0);

    // Semaphore 생성
    sem_t *sem = sem_open("/chat_sem", O_CREAT, 0666, 1);

    while (1) {
        printf("You: ");
        char msg[256];
        fgets(msg, sizeof(msg), stdin);

        if (strncmp(msg, "quit", 4) == 0)
            break;

        // Critical Section
        sem_wait(sem);
        strcpy(ptr, msg);
        sem_post(sem);

        printf("Written safely!\n");
    }

    // 정리
    sem_close(sem);
    sem_unlink("/chat_sem");
    munmap(ptr, SHM_SIZE);
    close(fd);
    shm_unlink(SHM_NAME);

    return 0;
}

이제 안전합니다! 

Shared Memory의 특징

1. 파일처럼 보이지만 메모리

# SHM 확인
$ ls -l /dev/shm/
-rw-r--r-- 1 user user 4096 Feb 27 15:00 chat_shm

→ /dev/shm에 파일처럼 생김
→ 실제로는 RAM!

2. 프로세스 종료 후에도 남아있음

$ ./writer  # 실행 후 종료

$ ls /dev/shm/
chat_shm  # 여전히 존재!

→ 명시적으로 삭제 필요: shm_unlink()

3. 크기 제한

# 시스템 최대 크기 확인
$ cat /proc/sys/kernel/shmmax
18446744073692774399  # 약 16EB (충분함)

# 실제 사용 중인 SHM
$ ipcs -m

실무 활용 사례

1. 고성능 데이터베이스

PostgreSQL, Redis 등:
- Index를 SHM에 캐싱
- 여러 프로세스가 동시 접근
- 빠른 읽기 성능

2. 멀티미디어 처리

비디오/오디오 스트리밍:
- 프레임 버퍼를 SHM에
- Encoder/Decoder가 공유
- 복사 없이 처리 → 실시간 가능

3. IPC 최적화

대용량 데이터 전송:
- 파일 공유
- 메모리 캐시
- 공유 큐

주의사항

1. 동기화 필수!

// ❌ 위험
strcpy(shm_ptr, data);  // Race Condition!

// ✅ 안전
sem_wait(sem);
strcpy(shm_ptr, data);
sem_post(sem);

2. 크기 설정 필수

// ftruncate() 없으면 크기가 0!
shm_open(...);
ftruncate(fd, SIZE);  // 필수!
mmap(...);

3. 정리 필수

// 프로그램 종료 시
munmap(ptr, SIZE);
close(fd);
shm_unlink(SHM_NAME);  // 삭제!

안 하면 /dev/shm에 파일 계속 남음!

성능 측정

직접 벤치마크를 돌려봤습니다.

테스트 환경

CPU: Apple M1
RAM: 16GB
OS: macOS (Linux 유사)
데이터: 1MB

결과

// FIFO
for (int i = 0; i < 1000; i++) {
    write(fifo_fd, data, 1024);
}
→ 평균: 8.5ms

// Shared Memory
for (int i = 0; i < 1000; i++) {
    memcpy(shm_ptr, data, 1024);
}
→ 평균: 0.8ms

속도 차이: 약 10배!

디버깅 팁

SHM 확인

# 현재 SHM 목록
$ ls -lh /dev/shm/

# SHM 크기 확인
$ du -h /dev/shm/chat_shm
4.0K    /dev/shm/chat_shm

# SHM 내용 보기
$ cat /dev/shm/chat_shm
Hello, Shared Memory!

ipcs 명령어

# System V SHM (옛날 방식)
$ ipcs -m

# 특정 SHM 삭제
$ ipcrm -m <shmid>

gdb로 메모리 확인

$ gdb ./writer
(gdb) break main
(gdb) run
(gdb) print ptr
$1 = 0x7f1234567000

(gdb) x/10s 0x7f1234567000
0x7f1234567000: "Hello"

마치며

Shared Memory를 구현하면서 속도와 안전성의 트레이드오프를 배웠습니다.

배운 점:

  • 복사 없는 직접 접근 → 10배 빠름
  • 동기화는 직접 해야 함 (Semaphore)
  • ftruncate() 필수
  • shm_unlink()로 정리 필수
  • /dev/shm에서 확인 가능

FIFO는 간단하지만 느리고, Shared Memory는 빠르지만 복잡합니다. 상황에 맞게 선택하는 게 중요합니다.

'Dev > System Programming' 카테고리의 다른 글

FIFO (Named Pipe) : 프로세스 간 통신의 기본  (0) 2026.02.22
'Dev/System Programming' 카테고리의 다른 글
  • FIFO (Named Pipe) : 프로세스 간 통신의 기본
onepaperhoon
onepaperhoon
한장훈님의 블로그 입니다.
  • onepaperhoon
    OnePaperHoon Blog
    onepaperhoon
  • 전체
    오늘
    어제
    • 분류 전체보기 (14)
      • Dev (14)
        • System Programming (2)
        • Linux (0)
        • CS (0)
        • Network, Protocol (0)
        • Grapics (11)
        • Web, App (0)
        • Design Pattern (1)
      • Projects (0)
      • TIL (0)
      • Life (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • GitHub
  • 공지사항

  • 인기 글

  • 태그

    graphicapi
    c++
    cpp
    graphics
    IPC
    디자인 패턴
    glfw
    Vertex Shader
    shader
    Process
    named pipe
    공유 메모리
    싱글톤 패턴
    Pipe
    OpenGL
    Game
    3d
    C언어
    shared memory
    그래픽스
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
onepaperhoon
[IPC] Shared Memory - 가장 빠른 프로세스 간 통신
상단으로

티스토리툴바