본문 바로가기
운영체제

공유 메모리

by meanjung 2021. 7. 8.

개요

보통 프로세스에서 사용되는 메모리 영역은 해당 프로세스만 사용할 수 있다.

하지만 때때로 여러개의 프로세스가 특정 메모리 영역을 사용했으면 하는 때가 있다.

☞ 이때 공유 메모리를 사용해 실현할 수 있다.

 

프로세스는 시작시 혹은 실행 중에 이런 데이터를 저장하고 사용하기 위한 메모리 공간을 커널에 요구해 할당받아 사용하게 되는데, 이런 메모리 공간은 기본적으로 메모리를 요청한 프로세스만이 접근가능하도록 되어있다.

하지만 가끔은 여러개의 프로세스가 특정 메모리 공간을 동시에 접근해야할 필요성을 가질 때가 있을 것이다.

 

공유 메모리는 여러 IPC(inter process communication) 중에서 가장 빠른 수행속도를 보여준다.

 

그 이유는 하나의 메모리를 공유해서 접근하게 되므로, 데이터 복사와 같은 불필요한 오버헤드가 발생하지 않기에 빠른 데이터의 이용이 가능하다.

그러나 하나의 프로세스가 메모리에 접근중에 있을때, 또 다른 프로세스가 메모리에 접근하는 일이 발생하면 자칫 데이터가 훼손될 수 있으므로, 한 번에 하나의 프로세스가 메모리에 접근하고 있다는 것을 보증해야 한다.

 

관련 함수

#include <sys/types.h>

#include <sys/shm.h>

 

int shmget(key_t key, int size, int shmflg)

void *shmat( int shmid, const void *shmaddr, int shmflg)

int shmdt( const void *shmaddr)

int shmctl(int shmid, int cmd, struct shmid_ds *buf)


공유 메모리는 어떻게 할당되는가?

어떤 과정을 통해 접근가능한가?

공유 메모리의 생성 요청은 최초 공유 메모리 영역을 만드는 프로세스가 커널에 공유 메모리 공간의 할당을 요청하면서 이루어진다.

만들어진 공유 메모리는 커널에 의해 관리된다.

☞ 때문에 한 번 만들어진 공유 메모리는 os를 reboot하거나, 직접 공유 메모리 공간을 삭제시키지 않는한, 공유 메모리를 사용하는 모든 프로세스가 없어졌다고 하더라도, 계속 유지된다.

 

프로세스가 커널에 공유메모리 공간을 요청하면, 커널은 공유 메모리 공간을 할당시켜주고, 이들 공유 메모리 공간을 관리하기 위한 내부자료구조를 통해, 이들 공유 메모리를 관리하게 된다. 

이 자료는 shmid_ds라는 구조체에 의해 관리되며, shm.h에 정의되어있다. 

 

즉, shmid_ds는 할당된 공유 메모리 공간을 관리하는 내부 자료구조

 

shmget

커널에 공유 메모리 공간을 요청하기 위해 호출하는 system call 함수

key는 고유의 공유 메모리임을 알려주기 위해 사용된다.

새로운 공유 메모리 영역 생성 or 기존에 만들어져있던 공유 메모리 영역을 참조

arg 1 - key : 원하는 공유 메모리에 접근하기 위한 키/ 커널에 의해 관리됨

arg 2 - size : 공유 메모리의 최소 크기/ 새로운 공유 메모리를 생성하고자 한다면 크기를 명시해야 함. 존재하는 메모리를 참조한다면 0으로 명시

arg 3 - : 공유 메모리의 접근권한, 생성방식을 명시/ IPC_CREAT(key를 이용해 새로운 공유 메모리 공간을 만든다), IPC_EXCL/ 권한도 지정해줄 수 있다. u, g, o에 대한 읽기/쓰기 권한을 지정할 수 있다. 실행권한은 X

int shmid;
key_t keyval;

keyval = 1234;
shmid = shmget(keyval, 1024, IPC_CREAT | 0666)); 
if (shmid == -1)
{
    return -1;
}

shmat

일단 공유 메모리 공간을 생성했으면, 우리는 공유 메모리에 접근할 수 있는 int형의 식별자를 얻게 된 것.

shmat을 이용해 이 식별자에 '지금의 프로세스가 공유 메모리를 사용가능하도록' 덧붙임 작업을 해줘야 한다.

arg 1 - shmget을 이용해 얻어낸 식별자 번호

arg 2 - 메모리가 붙을 주소를 명시/ 0을 사용할 경우 커널이 메모리가 붙을 주소를 명시하게 된다./ 특별한 상황이 없다면 0을 사용하도록.

arg 3 - 해당 공유메모리에 대한 "읽기 전용", "읽기/쓰기 가능" 모드로 열 수 있다./ shm_rdonly를 지정하면 읽기 전용, 아무 값도 지정하지 않으면 읽기/쓰기 가능 모드로 열리게 된다.

 

shmdt

프로세스가 더 이상 공유메모리를 사용할 필요가 없을 경우 프로세스와 공유 메모리를 분리하기 위해 사용

하지만, 단지 현재 프로세스와 공유 메모리를 분리할 뿐. 공유메모리 내용을 삭제하진 않는다.

공유메모리를 커널상에서 삭제하려고 한다면 shmctl을 사용해야 한다.


실제 공유 메모리를 사용하는 예제

자식과 부모 프로세스 간에 어떻게 메모리가 공유되는지 보여준다.

int 형의 공유메모리 공간을 할당한 다음,

자식 프로세스에서 여기에 1씩을 더하고 부모 프로세스에서는 공유메모리 내용을 출력하는 과정.

#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <string.h> 
#include <unistd.h> 


int main()
{
    int shmid;
    int pid;

    int *cal_num;
    void *shared_memory = (void *)0;


    // 공유메모리 공간을 만든다.
    shmid = shmget((key_t)1234, sizeof(int), 0666|IPC_CREAT);

    if (shmid == -1)
    {
        perror("shmget failed : ");
        exit(0);
    }

    // 공유메모리를 사용하기 위해 프로세스메모리에 붙인다. 
    shared_memory = shmat(shmid, (void *)0, 0);
    if (shared_memory == (void *)-1)
    {
        perror("shmat failed : ");
        exit(0);
    }

    cal_num = (int *)shared_memory;
    pid = fork();
    if (pid == 0)
    {
        shmid = shmget((key_t)1234, sizeof(int), 0);
        if (shmid == -1)
        {
            perror("shmget failed : ");
            exit(0);
        }
        shared_memory = shmat(shmid, (void *)0, 0666|IPC_CREAT);
        if (shared_memory == (void *)-1)
        {
            perror("shmat failed : ");
            exit(0);
        }
        cal_num = (int *)shared_memory;
        *cal_num = 1;

        while(1)
        {
            *cal_num = *cal_num + 1;
            printf("child %d\n", *cal_num); 
            sleep(1);
        }
    }

    // 부모 프로세스로 공유메모리의 내용을 보여준다. 
    else if(pid > 0)
    {
        while(1)
        {
            sleep(1);
            printf("%d\n", *cal_num);
        }
    }
}

 


참고(출처)

https://www.joinc.co.kr/w/Site/system_programing/IPC/SharedMemory

 

공유 메모리의 사용

#include #include int shmget(key_t key, int size, int shmflg) void *shmat( int shmid, const void *shmaddr, int shmflg ) int shmdt( const void *shmaddr) int shmctl(int shmid, int cmd, struct shmid_ds *buf)

www.joinc.co.kr

 

'운영체제' 카테고리의 다른 글

OverlayFS 개념  (0) 2021.07.24
Samba  (0) 2021.07.11
파일 디스크립터  (0) 2021.07.10
LD_PRELOAD를 이용한 후킹  (0) 2021.07.08
리눅스 공유 메모리 개념 및 함수 설명  (0) 2021.07.06

댓글