프로세스 사이의 통신 - 공유 메모리, 세마포어

이동욱

2021/08/15

Categories: 네트워크

공유 메모리


  1. 공유 메모리 객체를 만드는 과정
  2. 공유 메모리 객체의 크기를 설정하는 과정
  3. 공유 메모리 객체를 프로세스 메모리 영역과 맵핑하는 과정
#include <sys/mman.h> // 함수 정의
#include <sys/stat.h> // mode 매크로의 정의
#include <fcntl.h> // 0_로 시작하는 상수 매크로의 정의

int shm_open(const char *name, int oflag, mode_t mode);
매크로 이름 설명
O_RDWR 객체를 읽기 쓰기가 가능한 상태로 설정한다.
O_RDONLY 객체를 읽기만 가능한 상태로 설정한다.
O_CREAT 해당 이름의 객체가 존재하지 않을 경우 새로운 객체를 생성한다.
O_EXCL 해당 이름의 객체가 존재하면 에러를 발생시킨다.
O_TRUNC 해당 이름의 객체가 존재하면 사이즈 0으로 만든다.
int ftruncate(int fd, off_t length);
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t off_set);
매크로 이름 설명
PROT_READ 데이터의 읽기 작업이 가능
PROT_WRITE 데이터의 쓰기 작업이 가능
PROT_EXEC 데이터의 실행이 가능
PROT_NONE 데이터의 접근이 불가능
#include <sys/mman.h>

int munmap(void *addr, size_t len);

공유 메모리 사용 예제

  • 공유 메모리 영역을 생성한 후 정수형 카운터를 관리한다.
  • 부모 프로세스와 자식 프로세스는 카운터 값을 각각 증가시킨다.
  • 부모 프로세스와 자식 프로세스 간에 공유되는 정보를 확인한다.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>

#define SM_NAME "/Test"

int main(int argc, char *argv[]) {
  int shmfd;
  int pid;
  int status;
  int *test_value;

  shmfd = shm_open(SM_NAME, O_RDWR | O_CREAT, 0777);
  if (shmfd == -1) {
    fprintf(stderr, "open error\n");
    exit(1);
  }

  if (ftruncate(shmfd, sizeof(int)) == -1) {
    fprintf(stderr, "truncate error\n");
    exit(1);
  }

  test_value = mmap(0, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
  close(shmfd);

  *test_value = 10;

  printf("test value: %d\n", *test_value);

  pid = fork();
  if (pid == 0) {
    *test_value = *test_value + 1;
    printf("child process test value: %d\n", *test_value);
    sleep(3);
    *test_value = *test_value + 1;
    printf("child process test value: %d\n", *test_value);
    exit(1);
  } else if (pid < 0) {
    fprintf(stderr, "fork failure\n");
    exit(1);
  }
  else {
    sleep(1);
    *test_value = *test_value + 5;
    printf("parent process test value: %d\n", *test_value);
    wait(&status);
  }
  shm_unlink(SM_NAME);
  return 0;
}

세마포어


크리티컬 섹션에 대한 접근 방법

  1. 현재 카운터 변수 값을 읽는다.
  2. 현재 카운터 변수의 값에 1을 더한 값을 계산한다.
  3. 카운터 변수의 값을 2)번 결과물로 대체한다.

  1. 세마포어 값이 양수일 때만 크리티컬 섹션에 진입할 수 있다.
  2. 프로세스는 크리티컬 섹션에 진입하면서 세마포어 값을 0으로 변경한다.
  3. 프로세스는 크리티컬 섹션을 빠져나오면서 세마포어 값을 증가시킨다.

세마포어의 사용

<oflag에 O_CREAT가 설정된 경우>
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);

<oflag에 OCREAT가 설정되지 않은 경우>
sem_t *sem_open(const char *name, int oflag);
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);

세마포어와 공유 메모리

  • 공유 메모리 영역을 한 후 정수형 카운터를 관리한다.
  • 부모 프로세스와 자식 프로세스는 카운터 값을 각각 증가시킨다.
  • 부모 프로세스와 자식 프로세스 간에 공유되는 정보를 확인한다.
  • 부모 프로세스와 자식 프로세스가 공동으로 접근할 수 있는 공유 메모리의 동기화를 위해서 세마포어를 사용한다.
nclude <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
#include <semaphore.h>

#define SM_NAME "/Test"
#define SEM_NAME "/SemTest"

int main(int argc, char *argv[]) {
  int shmfd, pid, status, i;
  int *test_value;
  sem_t *sem;

  sem = sem_open(SEM_NAME, O_RDWR | O_CREAT, 0777, 1);
  if (sem == SEM_FAILED) {
    fprintf(stderr, "sem open error\n");
    exit(1);
  }

  shmfd = shm_open(SM_NAME, O_RDWR | O_CREAT, 0777);
  if (shmfd == -1) {
    fprintf(stderr, "shm open error\n");
    exit(1);
  }

  if (ftruncate(shmfd, sizeof(int)) == -1) {
    fprintf(stderr, "truncate error\n");
    exit(1);
  }

  test_value = mmap(0, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
  close(shmfd);
  *test_value = 10;
  printf("test value: %d\n", *test_value);

  pid = fork();
  if (pid == 0) { // child process
    for (i = 0; i < 10; i++) {
      sem_wait(sem);
      *test_value = *test_value + 1;
      printf("child process test value: %d\n", *test_value);
      sem_post(sem);
    }
    exit(1);
  } else if (pid < 0) {
    fprintf(stderr, "fork failure\n");
    exit(1);
  } else {
    for (i = 0; i < 10; i++) {
      sem_wait(sem);
      *test_value = *test_value + 5;
      printf("parent process test value: %d\n", *test_value);
      sem_post(sem);
    }
    wait(&status);
  }
  
  shm_unlink(SM_NAME);
  sem_unlink(SEM_NAME);
  return 0;
}

참고 문헌


>> Home