강좌 & 팁
프로세서간의 데이터 통신(IPC) 방법에는 여러 가지가 있습니다만, 그중에 변수를 공유하는 방법이 있습니다. 말 그대로 공유 메모리가 되겠습니다. 다른 IPC 방법에 비해 공유 메모리 사용의 장점은 모든 프로세서가 특별한 함수를 사용할 필요 없이, 마치 자신의 변수를 사용하듯이 처리하면 됩니다. 또한 생성된 공유 메모리는 식별자만 알면 어느 프로세서라도 사용할 수 있기 때문에 프로그램 확장이 편하며, 기존 프로그램을 수정할 필요 없이 모니터링할 수 있어 디버깅에도 사용할 수 있습니다.
- 공유 메모리 사용하는 모든 프로세서는 마치 자신의 변수를 사용하듯 처리한다.
- 식별자만 알고 있다면 모든 프로세서에서 사용이 가능하다.
- 새로운 프로세서 추가로 기능 확장이 가능하다.
- 공유 메모리를 모니터링하여 디버깅에 사용할 수 있다.
공유 메모리는 프로세서의 요청으로 커널에 의해 생성되며 관리됩니다. 그러나 커널이 공유 메모리의 안전을 보장해 주지 않습니다. 즉, 두 개 이상의 프로세서가 공유 메모리의 같은 부분을 읽을 수 있지만, 동시에 쓰기를 해서는 안 되며 프로세서에서 쓰기에 대한 안정성을 염두해서 작성해야 합니다. 그러므로 읽기는 자유롭게 해도 쓰기는 하나의 프로세서에서 실행하도록 하는 것이 안전합니다.
공유 메모리의 사용을 그림으로 정리하면 아래와 같습니다. 그림 설명은 프로세서 A와 B가 같은 공유 메모리를 사용하고 있는 예를 들어 설명합니다.
- 우선 프로세스 A 가 공유 메모리를 생성합니다.
- 프로세스 A 가 공유 메모리 영역을 자신의 메모리 영역으로 첨부해야 하는데,
이유는 그렇게 해야 자신의 메모리인 것처럼 사용할 수 있기 때문입니다.
- 공유 메모리를 자신의 메모리처럼 쓰기를 수행합니다.
- 프로세스 B 가 공유 메모리를 찾습니다.
- 공유 메모리를 찾았다면 프로세스 B 도 자신의 메모리 영역에 공유 메모리를 첨부합니다.
- 프로세서 B는 공유 메모리를 자신의 메모리를 이용하듯 데이터를 읽어 들입니다.
- shmget() 공유 메모리 생성
- shmat() 공유 메모리를 자기 메모리처럼 사용하기 위하여 프로세스의 메모리에 붙이기
- shmdt() 프로세스 메모리 영역에서 공유 메모리를 분리
- shmctl() 공유 메모리 정보 읽기/변경/삭제
공유 메모리 사용 순서와 사용 함수는 아래와 같습니다.
주의하실 것은 한 번 만들어진 공유 메모리는 재부팅하거나 직접 공유 메모리를 삭제하지 않는 한 제거 되지 않습니다.
공유 메모리를 사용는 모든 프로세서가 종료 되어도 사라지지 않으므로 이점에 유의하세요.
예제: 프로세서 A
프로세서 A는 공유 메모리를 문자열로 사용하고, 1초마다 숫자를 증가 시키면서 그 숫자를 공유 메모리의 문자열 변수에 출력하게 합니다.
#include <stdio.h> #include <unistd.h> #include <sys/ipc.h> #include <sys/shm.h> #define KEY_NUM 9527 #define MEM_SIZE 1024 int main( void) { int shm_id; void *shm_addr; int count; if ( -1 == ( shm_id = shmget( (key_t)KEY_NUM, MEM_SIZE, IPC_CREAT|0666))) { printf( "공유 메모리 생성 실패\n"); return -1; } if ( ( void *)-1 == ( shm_addr = shmat( shm_id, ( void *)0, 0))) { printf( "공유 메모리 첨부 실패\n"); return -1; } count = 0; while( 1 ) { sprintf( (char *)shm_addr, "%d", count++); // 공유 메모리에 카운터 출력 sleep( 1); } return 0; }
예제: 프로세서 B
프로세서 B는 프로세서 A가 생성하고 1초마다 내용을 갱신하는 문자열 별수를 화면에 출력합니다.
#include <stdio.h> #include <unistd.h> #include <sys/ipc.h> #include <sys/shm.h> #define KEY_NUM 9527 #define MEM_SIZE 1024 int main( void) { int shm_id; void *shm_addr; if ( -1 == ( shm_id = shmget( (key_t)KEY_NUM, MEM_SIZE, IPC_CREAT|0666))) { printf( "공유 메모리 생성 실패\n"); return -1; } if ( ( void *)-1 == ( shm_addr = shmat( shm_id, ( void *)0, 0))) { printf( "공유 메모리 첨부 실패\n"); return -1; } while( 1 ) { printf( "%s\n", (char *)shm_addr); // 공유 메모리를 화면에 출력 sleep( 1); } return 0; }
예제에서는 문자열 포인터 하나만 사용했지만, 다양한 변수를 하나의 스트럭쳐로 구성해서 스트럭쳐 포인터로 이용하면 매우 편리합니다. 참고하세요. ^^