Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>
Docbook 원문

shmat(2)

1장. shmat(2)

차례
1.1. 사용법
1.2. 설명
1.3. 반환값
1.4. 에러
1.5. 예제
1.6. 참고문헌

공유메모리 관련 연산


1.1. 사용법

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

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


1.2. 설명

shmat()는 공유메모리 식별자인shmid에 공유 메모리 세그먼트를 붙이기 위해서 사용한다. 붙이는 영역은 shmaddr로 결정할 수 있다.

만약 shmaddr가 NULL이라면 시스템은 적당한 사용하지 않는 메모리(:12) 영역을 붙이게 된다.

만약 shmaddr가 NULL이 아니고 SHM_RND가 shmflg로 지정되어 있다면 shmaddr은 SHMLBA의 배수의 주소로 연결이 발생한다. 그렇지 않으면 shmaddr은 연결할 수 있는 정렬된 페이지 주소여야 한다.

만일 SHM_RDONLY가 shmflg에 지정되었다면, 세그먼트는 읽기전용이 되며 공유메모리 영역에 접근하고자 하는 프로세스는 읽기전용허가 접근권을 가져야 한다. 그렇지 않을경우 세그먼트는 읽기/쓰기로 붙여지며 프로세스(:12)는 (반드시)읽기/쓰기 허가권을 가져야한다. 쓰기전용 공유메모리(:12) 세그먼트를 위한 플래그는 없다.

프로세스가 종료되면 연결된 세그먼트는 자동적으로 분리된다. 동일한 세그먼트는 읽기와 읽기/쓰기로 한번이상 연결시킬 수 있다.

shmat가 성공하면 시스템은 shmid_ds구조체의 멤버들을 아래와 같이 업데이트 시킨다.

  1. shm_atime을 현재 시간으로 수정한다.

  2. shm_lpid를 현재 호출한 프로세스의 ID로 설정한다.

  3. shm_nattch는 1 증가 시킨다.

공유메모리 세그먼트가 삭제로 표시될 때에도 마찬가지로 분리된다.

shmdt()는 공유 메모리 영역으로 부터 shmaddr 주쇼를 분리 시키기 위해서 사용한다. 공유메모리 영역의 분리는 shmat 시스템 콜로 연결된 값과 동일한 shmaddr을 가지고 있는 연결된 영역들중 하나여야 한다.

shmdt()가 성공적으로 호출되면 shmid_ds구조체의 멤버를 다음과 같이 변경한다.

  1. shm_dtime을 현재 시간으로 변경한다.

  2. shm_lpid를 현재 호출한 프로세스의 ID로 변경한다.

  3. shm_nattch을 1 감소 시킨다. 만약 값이 0이되고 세그먼트에 삭제표시가 되어 있다면 세그먼트는 삭제된다.

호출 프로세스의 유저공간에 점유된 영역은 대응이 풀리지 않는다.


1.3. 반환값

성공하면 attach된 shared memory segment를 반환하고 실패하면 -1을 반환한다.


1.4. 에러

EACCES

호출한 프로세스가 붙이기 원하는 영역에 대해서 권한을 가지고 있지 않다.

EINVAL

잘못된 shmid 값, 혹은 잘못된 shmaddr 값을 가지고 있다.

ENOMEM

메모리할당(:12)을 할 수 없다.


1.5. 예제

#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;


    // 공유메모리 공간을 만든다.
		// 크기는 4byte로 한다.
    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);
        }
    }
}