시스템 소프트웨어

공유 메모리 (Shared Memory)

masimelo 2023. 3. 11. 22:24

공유메모리

공유메모리

  • 공유메모리 = 프로세스 간 통신을 위한 메커니즘
  • 기본적으로 프로세스는 다른 프로세스의 메모리 영역에 접근이 불가능함
    • 가끔은 여러 개의 프로세스가 특정 메모리 영역을 동시에 접근해야 할 필요성을 가질 때가 있음
  • 여러 개의 프로세스가 동일한 메모리 영역에 접근할 수 있도록 제공함
    • 서로 다른 프로세스가 특정한 논리 메모리 영역에 접근하여 데이터를 읽고 쓸 수 있음
  • 여러 ipc 중에서 가장 빠른 수행 속도를 보여줌
    • 하나의 메모리 영역을 공유해서 접근하게 되므로, 데이터 복사와 같은 불필요한 오버헤드가 발생하지 않기 때문
  • 동기화 기능을 제공하지 않기 때문에 세마포어 등의 메커니즘을 사용하여 메모리 영역의 접근을 동기화해야 함

공유 메모리 함수

ftok()

#include < sys/ipc,h>
#include <sys/types.h>

key_t ftok(const char * pathname, int proj_id);
  • 설명
    • System V IPC에서 사용할 키를 생성 함
  • 인자
    • pathname : 키를 생성할 경로 또는 이름
    • proj_id : 같은 경로의 키에 대해서 구분하기 위한 값
  • 반환
    • 성공하면 키값
    • 실패하면 -1

shmget()

#include <sys/shm.h>
#include <sys/types.h>

int shmget(key_t key, size_t size, int shmflag);
  • 설명
    • 공유 메모리를 생성하고 접근할 수 있는 식별자를 반환함
  • 인자
    • key : 공유 메모리를 식별하는 키 값
    • size : 생성하고자 하는 고유 메모리의 크기
    • shmflag : 공유 메모리의 생성에 관한 플래그
  • 반환
    • 성공하면 공유 메모리 식별자
    • 실패하면 -1

shmat()

#include <sys/shm.h>
#include <sys/types.h>

void *shmat(int shmid, const void * shmaddr, int shmflag);
  • 설명
    • 프로세스가 공유메모리를 사용할 수 있도록 연결함
  • 인자
    • shmid : 공유 메모리의 식별자
    • shmaddr : 공유 메모리가 연결될 영역의 주소 ( 대부분 커널에서 설정하도록 NULL을 사용)
    • shmflag : 공유 메모리 영역의 읽기/쓰기에 관한 플래그
      • 0
        • 공유 메모리에 데이터를 읽고 쓸 수 있음
      • SHM_RDONLY
        • 공유 메모리를 읽기 전용으로 연결함
  • 반환
    • 성공하면, 공유 메모리 영역의 시작 주소
    • 실패하면 -1

shmdt()

#include <sys/shm.h>

int shmdt(const void * shmaddr);
  • 설명
    • 공유 메모리를 현재 프로세스로부터 분리함
  • 인자
    • shmaddr : 공유 메모리 영역의 시작 주소
  • 반환
    • 성공하면 0
    • 실패하면 -1

strucrt shmid_ds

#include <sys/shm.h>
#include <sys/types.h>
struct shmid_ds
{
    struct ipc_perm shm_perm; // 퍼미션
    int shm_segsz;            // 메모리 공간의 크기
    time_t shm_dtime;         // 마지막 attach 시간
    time_t shm_dtime;         // 마지막 detach 시간
    time_t shm_ctime;         // 마지막 변경 시간
    unsigned short shm_cpid;  // 생성프로세스의 pid
    unsigned short shm_lpid;  // 마지막으로 작동한 프로세스의 pid
    short shm_nattch;         // 현재 접근한 프로세스의 수
};

shmctl()

#include <sys/mhm.h>

int shmctl(int shmid, int cmd, shruct shmid_ds * buf);
  • 설명
    • 공유메모리를 제어함
  • 인자
    • shmid : 공유 메모리의 식별자
    • cmd : 제어동작에 관한 플래그
      • IPC_RMID : 지정한 공유 메모리를 제거함
      • IPC_SET : 공유메모리의 정보를 지정한 정보로 변경함
      • IPC_STAT : 공유 메모리의 정보를 지정한 메모리 공간에 저장함
    • buf : 제어에 사용되는 공유 메모리 구조체의 메모리 공간에 대한 포인터
  • 반환
    • 성공하면 0
    • 실패하면 -1
  • 예시
    • 서버
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>

#define MAX_SHM_SIZE 512

void signalHandler(int signum);
void myfunc(void);

key_t mykey=0;
int shmid =0;
int *shmaddr = NULL;

int main(int argc, char const *argv[]){
    mykey = ftok("Myshmkey",2);
    shmid = shmget(mykey, MAX_SHM_SIZE, IPC_CREAT|0600);
    shmaddr = shmat(shmid, NULL, 0);

    signal(SIGINT, signalHandler);
    signal(SIGUSR1,signalHandler);

    while(1){
        puts("Wait...");
        pause();
    }
    return 0;
}

void signalHandler(int signum){
    struct shmid_ds buf;

    if(signum == SIGINT){
        shmdt(shmaddr);
        shmctl(shmid,IPC_RMID, NULL);
        exit(0);
    }
    else if(signum == SIGUSR1){
        myfunc();
    }
}

void myfunc(void){
    struct shmid_ds buf;
    int data=0;

    memcpy(&data, shmaddr,sizeof(int));
    printf("Receive : %d\\n",data);

    data +=1;
    memcpy(shmaddr, &data, sizeof(int));
    printf("Send : %d \\n",data);

    shmctl(shmid, IPC_STAT,&buf);
    kill(buf.shm_lpid,SIGUSR1);
}
  • 클라이언트
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>

#define MAX_SHM_SIZE 512

void signalHandler(int signum);
void myfunc(void);

key_t mykey =0;
int shmid=0;
int *shmaddr = NULL;

int main(int argc, char const * argv[]){
    struct shmid_ds buf;
    int data = 0;

    mykey = ftok("Myshmkey",2);
    shmid=shmget(mykey, MAX_SHM_SIZE, IPC_CREAT);
    shmaddr = shmat(shmid, NULL,0);

    signal(SIGUSR1, signalHandler);

    while(1){
        printf("<< ");
        scanf("%d", &data);

        fflush(stdout);
        fflush(stdin);

        memcpy(shmaddr, &data, sizeof(int));
        shmctl(shmid, IPC_STAT,&buf);
        kill(buf.shm_cpid,SIGUSR1);

        pause();
    }
    return 0;
}

void signalHandler(int signum){
    int data=0;
    if(signum == SIGUSR1){
        memcpy(&data, shmaddr,sizeof(int));
        printf(">> %d\\n",data);
    }
}