290 likes | 641 Views
Linux System Programming. Lecture #11 – 공유메모리 (Shared Memory). 공유메모리 (Shared Memory) (1). 공유메모리 정의 : 두 개이상의 프로세스가 실제 메모리의 일부를 공유하여 통신할 수 있는 IPC 도구 통신하려는 프로세스는 우선 공유 메모리를 할당받는다 프로세스는 할당된 공유 메모리를 자신의 가상주소공간 일부에 붙여 (attach) 메모리에 데이터를 읽고 쓰는 것가 동일한 방법으로 필요한 데이터를 읽거나 전송하려는 데이터를 기록하여 상호 통신한다
E N D
Linux System Programming Lecture #11 –공유메모리(Shared Memory)
공유메모리(Shared Memory) (1) • 공유메모리 정의 : • 두 개이상의 프로세스가 실제 메모리의 일부를 공유하여 통신할 수 있는 IPC 도구 • 통신하려는 프로세스는 우선 공유 메모리를 할당받는다 • 프로세스는 할당된 공유 메모리를 자신의 가상주소공간 일부에 붙여(attach) 메모리에 데이터를 읽고 쓰는 것가 동일한 방법으로 필요한 데이터를 읽거나 전송하려는 데이터를 기록하여 상호 통신한다 • 프로세스간의 통신이 종료되면 공유 메모리를 가상주소공간에서 떼어내고(detach) 공유 메모리를 해제한다 • IPC 도구 중에서 가장 효율적 • 시스템 간의 이식성이 낮음 • 프로세스간의 메모리 공유를 위해 별도의 하드웨어 지원이 필요 • 공유 메모리를 사용한 프로그램을 하드웨어 지원이 없는 시스템에서는 사용불가 Linux System Programming
공유메모리(Shared Memory) (2) • 공유 메모리 시스템 호출 : • shmget –공유 메모리를 새롭게 할당하거나 할당된 공유 메모리의 핸들을 반환한다 • shmctl –공유 메모리와 관련된 상태 변수값을 변경하거나 공유 메모리를 제거한다 • shmat –공유 메모리를 프로세스의 가상주소공간에 논리적으로 부착(attach)한다 • shmdt –프로세스의 가상주소공간으로부터 공유 메모리를 분리한다 Linux System Programming
shmget() 프로세스 P1 프로세스 P2 공유메모리 shmat() shmat() shmdt() shmdt() 가상주소: 10000 가상주소: 20000 shmctl() 공유메모리(Shared Memory) (3) • 공유 메모리 시스템 호출 : Linux System Programming
공유메모리(Shared Memory) (4) • 공유 메모리의 생성: shmget() Linux System Programming
공유메모리(Shared Memory) (5) • 공유 메모리의 생성: shmget() • 공유 메모리 구조체 Linux System Programming
공유메모리(Shared Memory) (6) • 공유 메모리의 생성: shmget() • 공유 메모리 구조체의 초기화 Linux System Programming
공유메모리(Shared Memory) (7) • 공유 메모리의 제어: shmctl() Linux System Programming
공유메모리(Shared Memory) (8) • 공유 메모리의 제어: shmctl() • shmctl 시스템 호출의 명령어 Linux System Programming
공유메모리(Shared Memory) (9) • 공유 메모리의 연산: shmat()/shmdt() Linux System Programming
예제 프로그램 (1) • 예제 11-1 • 학원 강좌 예약 시스템 프로그램 • 부모 프로세스는 강좌 예약 정보를 갖는 공유 메모리을 할당하고, 공유 메모리에 대한 상호배제를 위한 세마포어를 생성한다 • 자식 프로세스을 생성하여 강좌 예약을 수행하는데, 자식 프로세스는 주기적으로 강좌 예약을 수행하도록 시뮬레이션하며, 더 이상 예약할 좌석(seat)가 없으면 종료한다 • 부모 프로세스는 모든 자식 프로세스가 종료할 때까지 기다렸다가 세마포어와 공유 메모리를 제거하고 종료한다 Linux System Programming
예제 프로그램 (2) // // file name: ex11-1.h // struct CLASS { char class_number[6]; char date[6]; char title[50]; int seats_left; } typedef struct CLASS class_t; Linux System Programming
예제 프로그램 (3) // file name: ex11-1a.c // #include <stdio.h> #include <memory.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #include "ex11-1.h" class_t class = { "1001", "120186", "C Language for Programmers", 15 }; #define NCHILD 3 int child[NCHILD]; char *shm_ptr, *shmat(); int semid, shmid; char ascsemid[10], ascshmid[10]; char pname[14]; void rpterror(); int main(int argc, char *argv[]) { int i; Linux System Programming
예제 프로그램 (4) strcpy(pname, argv[0]); shm_init(); sem_init(); for(i=0; i < NCHILD; i++) { child[i] = fork(); switch(child[i]) { case -1: rpterror("fork-failure"); exit(1); case 0: sprintf(pname,"ex11-1b%d",i+1); execl("ex11-1b", pname, ascshmid, ascsemid, (char *) 0); perror("execl faild"); exit(2); } } wait_and_wrap_up(); } shm_init() { shmid=shmget(IPC_PRIVATE, sizeof(class), 0600|IPC_CREAT); if(shmid == -1) { perror("shmget failed"); exit(3); } shm_ptr = shmat(shmid, (char *) 0, 0); if(shm_ptr == (char *) -1) { perror("shmat failed"); exit(4); } memcpy(shm_ptr,(char *) &class, sizeof(class)); sprintf(ascshmid,"%d", shmid); } Linux System Programming
예제 프로그램 (5) sem_init() { if((semid=semget(IPC_PRIVATE, 1, 0600| IPC_CREAT)) == -1) { perror("semget failed"); exit(5); } if((semctl(semid, 0, SETVAL,1)) == -1) { printf("parent: semctl, SETVAL failed\n"); exit(6); } sprintf(ascsemid,"%d",semid); } wait_and_wrap_up() { int wait_rtn, w, ch_active = NCHILD; while(ch_active > 0) { wait_rtn = wait((int *) 0); for(w=0; w < NCHILD; w++) if(child[w] == wait_rtn) { ch_active--; break; } } printf("Parent removing shm and sem\n"); shmdt(shm_ptr); shmctl(shmid, IPC_RMID); semctl(semid, 0, IPC_RMID, 0); exit(0); } Linux System Programming
예제 프로그램 (6) void rpterror(string) char *string; { char errline[50]; sprintf(errline,"%s %s",string, pname); perror(errline); } Linux System Programming
예제 프로그램 (7) // file name: ex11-1b.c // #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #include "ex11-1.h" class_t *class_ptr; char *memptr, *shmat(), *pname; int semid, shmid, ret; struct sembuf lock = { 0, -1, 0}; struct sembuf unlock = { 0, 1, 0}; void rpterror(); int main(int argc, char *argv[]) { if(argc < 3) { fprintf(stderr, "Usage: %s shmid semid\n", argv[0]); exit(1); } pname = argv[0]; sscanf(argv[1],"%d", &shmid); memptr = shmat(shmid, (char *) 0, 0); Linux System Programming
예제 프로그램 (8) if(memptr == (char *) -1) { rpterror("shmat failed"); exit(2); } class_ptr = (class_t *) memptr; sscanf(argv[2], "%d", &semid); sell_seats(); ret = shmdt(memptr); exit(0); } sell_seats() { int all_out = 0; srand((unsigned) getpid()); while(! all_out) { /* loop to sell all seats */ if(semop(semid, &lock, 1) == -1) { rpterror("semop lock failed"); exit(4); } if(class_ptr -> seats_left > 0) { class_ptr -> seats_left--; printf("%s SOLD SEAT -- %2d left\n", pname, class_ptr->seats_left); } Linux System Programming
예제 프로그램 (9) else { all_out++; printf("%s sees no seats left\n", pname); } ret = semop(semid, &unlock, 1); if(ret ==-1) { rpterror("semop unlock failed"); exit(4); } sleep((unsigned) rand() %10 +1); } } void rpterror(string) char *string; { char errline[50]; sprintf(errline,"%s %s",string, pname); perror(errline); } Linux System Programming
예제 프로그램 (10) • 예제 11-2 • 세마포어와 공유 메모리를 이용하여 버퍼의 자료를 생산하고 소비하는 생산자/소비자(producer/consumer) 프로그램 • 생산자는 공유 메모리를 할당하여 버퍼를 설정한다 • 생산자와 소비자 사이에 버퍼 접근을 위한 동기화를 위해 2 개의 세마포어를 생성하여 사용한다 • 버퍼 쓰기 동기화(consumed 동기화) - 생산자는 소비자가 버퍼의 자료를 읽고 간 후에 새로운 자료를 버퍼에 쓴다 • 버퍼 읽기 동기화(produced동기화) - 소비자는 생산자가 버퍼에 새로운 자료를 쓴 후에 자료를 읽어간다 Linux System Programming
예제 프로그램 (11) // file name: ex11-2a.c // /* producer program: producer program sets up a buffer to be read by a consumer. semaphore are used to ensure taht producer dosen't overwrite an unread buffer and consumer dosen't read the same data more than once. */ #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #define MSG_SIZE 30 #define MAX 5 main() { char *getenv(); key_t ftok(); char *shmat(); key_t key; void perror(), exit(); Linux System Programming
예제 프로그램 (12) /* two semaphores in a set index 0 - incremented when producer has reset buffer - tested and decremented by consumer to check if buffer has been reset index 1 - incremented when consumer has read buffer - tested and decremented by producer to check if consumer is done. */ static struct sembuf wait_consumed = { 1, -1, 0}; static struct sembuf signal_produced = { 0, 1, 0}; int semid, shmid; char *message; int i; if((key = ftok(getenv("HOME"), 'u')) == (key_t) -1) { fprintf(stderr,"ftok key formation error\n"); exit(1); } semid = semget(key, 2, IPC_CREAT | 0660); if(semid == -1) { perror("producer semget():"); exit(2); } Linux System Programming
예제 프로그램 (13) shmid = shmget(key, MSG_SIZE, IPC_CREAT | 0660); if(semid == -1) { perror("producer shmget():"); exit(3); } message = shmat(shmid, (char *) 0, 0); for(i=1; i < MAX; i++) { /* producer has to go first */ if(i>1) semop(semid, &wait_consumed, 1); sprintf(message, "message %d", i); semop(semid, &signal_produced, 1); } shmdt(message); sleep(5); /* allow consumer to digest last message */ /* alternatively a DELIMITER string could be placed in shared memory when seen by the consumer, it would exit. the producer would do shmctl (..., IPC_STAT, ....) and when shm_attach == 1, it would remove the two IPC facilities */ shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0); shmctl(shmid, 0, IPC_RMID); } Linux System Programming
예제 프로그램 (14) // file name: ex11-2b.c // /* consumer program: producer program sets up a buffer to be read by a consumer. semaphore are used to ensure taht producer dosen't overwrite an unread buffer and consumer dosen't read the same data more than once. */ #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #define MSG_SIZE 30 int main(int argc, char *argv[]) { /* two semaphores in a set index 0 - incremented when producer has reset buffer - tested and decremented by consumer to check if buffer has been reset index 1 - incremented when consumer has read buffer - tested and decremented by producer to check if consumer is done. */ Linux System Programming
예제 프로그램 (15) key_t key; static struct sembuf wait_produced = { 0, -1, 0}; static struct sembuf signal_consumed = { 1, 1, 0}; int semid, shmid; char *message; int rtn; if((key = ftok(getenv("HOME"), 'u')) == (key_t) -1) { fprintf(stderr,"ftok key formation error\n"); exit(1); } /* either producer or consumer might be the creator but producer will be the remover of IPC resources. producer and consumer's effective uid must be the same. */ semid = semget(key, 2, IPC_CREAT | 0660); if(semid == -1) { perror("producer semget():"); exit(2); } Linux System Programming
예제 프로그램 (16) shmid = shmget(key, MSG_SIZE, IPC_CREAT | 0660); if(semid == -1) { perror("producer shmget():"); exit(3); } message = shmat(shmid, (char *) 0, SHM_RDONLY); while(1) { rtn = semop(semid, &wait_produced, 1); /* when producer is done semid will be IPC_RMID forcing break */ if(rtn == -1) { perror("consumer - semop on wait_consumed"); break; } printf("%s recevied: %s\n", argv[0], message); semop(semid, &signal_consumed, 1); } shmdt(message); } Linux System Programming