본문 바로가기
컴퓨터공학기초 개념/시스템 프로그래밍

27. 프로세스 - IPC 기법(shared memory)

by devraphy 2021. 9. 21.

0. 시작하기전에

- 이전 포스팅에서 IPC기법 중 pipe와 message queue 기법을 직접 구현해 보았다. 

 

- 이번 포스팅에서는 다른 종류의 IPC기법을 실습해 볼 예정이다. 


1. ipcs 명령어 

- ipcs 명령어는 현재 커널공간에 생성되어 있는 message queue, 공유메모리, 세마포어를 확인할 수 있다.

- 아래의 사진처럼, 현재 커널 공간을 활용하고 있는 메모리를 보여준다. 

 

a) 메세지 큐를 송수신 해보자. 

- 우선, 이전 포스팅에서 만들어 놓은 메세지 큐 송수신 프로그램을 실행시켜보자. 

- 위의 사진은 Message queue를 전송한 후 ipcs명령어를 입력한 것이다.

- message queue가 50bytes의 크기로, 1개의 메세지를 담고 있다는 것을 보여준다. 

- 그렇다면 메세지를 수신하고 나면 커널영역의 해당 메모리는 사라질까?

 

 

- 위의 사진처럼, 해당 메모리는 사라지지 않는다. 

- 다만, 크기와 메세지 수가 0으로 변한 것을 알 수 있다. 

- 메세지를 수신받았다고, message queue를 사용하지 않겠다는 의미가 아니다.

- message queue를 다시 사용할 수 있기 때문에, 메모리 상에서는 남아있게 된다. 

- 만약 메세지 큐를 삭제하고 싶다면, msgctl() 함수를 이용해 제거할 수 있다는 것을 참고하자.

 


2. shared memory(공유 메모리)

- 공유 메모리 기법은 커널 영역의 메모리에 변수를 할당하여, 공유 변수처럼 사용하는 방식이다. 

- 변수를 생성하여 값을 바꾸는 방식으로, 변수를 이용해 소통을 한다. 

- message queue와 마찬가지로, 공유 메모리는 고유의 key를 갖고 있으며

- 고유 key 값을 통해 여러 프로세스의 접근이 가능하도록 설계되어있다. 

 

 

a) 공유 메모리 및 key 생성

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

// key: 임의 숫자 또는 ftok 함수를 통해 생성된 키 값
// size: 공유 메모리 크기 
// shmflg: 공유 메모리 속성 및 권한
// 리턴 값: 공유 메모리 식별자를 반환 
int shmget(key_t key, size_t size, int shmflg);

// 예시
shmid = shmget((key_t)1234, SIZE, IPC_CREAT|0666));

 

 

b) 공유 메모리와 변수 Mapping

- 커널영역에 공유 메모리 영역을 할당하면서 동시에 key를 생성하였다.

- 이제 이 공유메모리를 프로세스의 어떤 변수에 mapping(연결)을 시켜야 한다. 

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

// shmid: shmget 함수로 생성한 공유 메모리 식별자
// shmaddr: 공유 메모리 연결 주소 (보통 (char*)NULL로 설정하면, 알아서 적절한 주소로 연결)
// shmflg: 공유 메모리의 읽기/쓰기 권한(0이면 읽기/쓰기 가능, SHM_RDONLY면 읽기만 가능)
// 리턴 값: 성공시 연결된 공유 메모리의 시작 주소를 반환 
void *shmat(int shmid, cont void *shmaddr, int shmflg);

// 예시
shmaddr = (char *)shmat(shmid, (char *)NULL, 0);

* shmat = shared memory attach

* shmaddr = shared memory address

 

 

c) 공유 메모리 해제 

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

int shmdt(char *shmaddr);

* shmdt = shared memory detach

 

 

d) 공유 메모리 읽기

- 포인터 변수처럼 사용하면 된다. 

printf("%s\n", (char *)shmaddr);

 

 

e) 공유 메모리에 쓰기

strcpy((char *)shmaddr, "Linux Programming");

 

 

f) 공유 메모리 영역을 삭제하는 방법 

- message queue에서 msgctl()을 사용하여 message queue 메모리를 삭제하는 것처럼,

- 공유 메모리도 shmctl()을 사용하여 삭제할 수 있다. 

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

// shmid: shmget 함수로 생성한 공유 메모리 식별자
// cmd: 수행할 제어 기능 (예: IPC_RMID - shmid로 지정한 공유 메모리 제거)
// buf: 제어 기능에 사용되는 공유 메모리 구조체의 구조 
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

// 예시
shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL);

* shctl = shared memory control


3. Share Memory 실습 예제

#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main(void) {
        int shmid, pid;
        char *shmaddr_parent, *shmaddr_child; // 공유 메모리 영역을 할당할 포인터 변수
        shmid = shmget((key_t)1234, 10, IPC_CREAT|0664); // 키값 생성
        if(shmid == -1) {
                perror("shmget error\n");
                exit(1);
        }

        pid = fork(); // 자식 프로세스 생성
        if(pid > 0) { // 2.부모 프로세스
                wait(0); // 자식 프로세스의 exit() 호출까지 대기
                shmaddr_parent = (char *)shmat(shmid, (char *)NULL, 0);
                printf("%s\n", shmaddr_parent); // 공유 메모리 값을 읽음(read)
                shmdt((char *)shmaddr_parent);
        }
        else { // 1.자식 프로세스
                shmaddr_child = (char *)shmat(shmid, (char *)NULL, 0); // 공유 메모리 키를 변수에 매핑
                strcpy((char *)shmaddr_child, "Hello Parent!"); // 공유 메모리에 쓰기(write)
                shmdt((char *)shmaddr_child); // 포인터 변수를 공유 메모리에서 해제
                exit(0);
        }
        shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL); // 공유메모리를 커널영역에서 삭제
        return 0;
}

프로그램 실행 결과

 

댓글