1.02k likes | 1.91k Views
Task 통신 및 동기화 : Message Queue, Semaphore Shared Memory. Chapter #12. 강의 목차. IPC(Inter-Process Communication) 메시지 큐 (Message Queue) 세마포어 (Semaphore) 공유 메모리 (Shared Memory). Unix System Programming. 2. IPC(Inter-Process Communication). 동일한 플랫폼 상에서 유사하게 구현되어 ICP 도구로 별도 분류하기도 함.
E N D
Task 통신 및 동기화 :Message Queue, SemaphoreShared Memory Chapter #12
강의 목차 • IPC(Inter-Process Communication) • 메시지 큐(Message Queue) • 세마포어(Semaphore) • 공유 메모리(Shared Memory) Unix System Programming Unix System Programming 2
동일한 플랫폼 상에서 유사하게 구현되어 ICP 도구로 별도 분류하기도 함 IPC(Inter-Process Communication) (1) • 프로세스 통신 도구(IPC Facilites) : • 비동기적으로 동작하는 프로세스간의 통신을 위하여 운영체제가 제공하는 도구 • 종류: • Signal(신호) • Pipe(파이프) • Message Queue(메시지 큐) • Semaphore(세마포어) • Shared Memory(공유 메모리) • Socket(소켓) Linux System Programming
IPC(Inter-Process Communication) (2) • 프로세스 통신 도구 (IPC Facilites) : • 세마포어(Semaphore) • 프로세스 동기화와 자원 관리에 사용 • 프로세스간의 상호배제 문제 해결에 사용 • 공유 메모리(Shared Memory) • 가장 빠른 프로세스 통신 도구 • 하나 이상의 프로세스에 부착하여 서로 공유하여 접근 가능 • 프로세스간의 공유 메모리 접근을 위해 동기화가 필요 • 메시지 큐(Message Queue) • 프로세스들간에 이산적인 양의 데이터 송수신을 위해 사용 • 전송할 데이터를 메시지 형태로 생성하여 전달하고 메시지 수신을 통해 데이터 수신이 가능 • 인터넷 메일 서비스와 개념이 유사 Linux System Programming
IPC(Inter-Process Communication) (3) • IPC와 관련한 시스템 호출 함수: • IPC 시스템 호출 함수: Linux System Programming
IPC(Inter-Process Communication) (4) • IPC와 관련한 시스템 호출 함수: • get 시스템 호출 • 파일 열기 시스템 호출 open과 유사 • 새롭게 통신 도구를 생성하거나 이미 생성된 통신 도구에 대한 id를 반환하여 접근 가능하게 함 • 반환된 id는 파일 디스크립터와 비슷하게 동작 • 접근 허가 또한 파일 접근 허가와 비슷하게 규정 • ctl 시스템 호출 • 통신 도구에 관한 상태 정보 읽기 • 몇몇 상태 정보(소유자, 그룹, 접근 허가 등)에 대한 변경 • 통신 도구의 제거 기능 • op 시스템 호출 • 프로세스간의 데이터 전송을 실행 • 파일 시스템 호출 read/write와 유사 • Shmat는 파일의 open과 유사하고, shmdt는 파일의 close와 유사 Linux System Programming
key_t char device Inode # of file IPC(Inter-Process Communication) (5) • IPC 도구 식별자: • IPC 도구 식별자 – IPC key • 파일을 식별하기 위해 파일 이름을 사용하듯이 IPC 객체를 식별하기 위해 사용하는 정수형 숫자 • 프로세스들은 IPC key를 이용하여 IPC 자원을 공유 • 자료형: key_t (<sys/types.h>에 정의) • IPC key 변환 시스템 호출 – ftok(file_to_key) • IPC 도구의 공유를 편리하게 지원하기 위해 파일 경로명과 식별자를 IPC 도구에 부여하고, 이를 IPC key 값으로 변환하는 시스템 호출 Linux System Programming
IPC(Inter-Process Communication) (6) • IPC 도구 식별자: • IPC key 변환 시스템 호출 – ftok(file_to_key) Linux System Programming
IPC(Inter-Process Communication) (7) • IPC 도구의 상태 자료 구조: • 생성된 IPC 객체에 대한 상태 정보를 저장하는 구조체 • IPC 도구 유형별로 별도의 상태 구조체를 지원하나 다음의 접근 허가 구조를 공통으로 포함한다 • IPC 도구의 접근 허가 구조: struct ipc_perm • 파일의 접근 허가와 유사한 기능을 지원 • 접근 모드에서 실행 모드는 무의미함 Linux System Programming
IPC(Inter-Process Communication) (8) • IPC 도구 테이블 • IPC 도구 유형별로 생성된 IPC 객체를 관리하기 위해 운영체제가 유지하는 테이블 • IPC 도구 유형별로 각각의 테이블을 유지 • 파일 테이블과 유사한 개념 Linux System Programming
IPC(Inter-Process Communication) (9) • IPC 도구 관리 명령: • ipcs 명령 • 현재 사용중인 IPC 도구들의 상태(status)를 보여주는 명령 • IPC 타입, 사용자 ID, key 값 그리고 접근 허가 등을 볼 수 있음 • 옵션을 사용하여 지정된 유형의 IPC 도구 상태 정보만을 접근 가능 • -q : 메시지 큐, -m : 공유 메모리, -s : 세마포어 • ipcrm 명령 • IPC 객체를 제거하는 명령 • IPC 도구 유형 및 key 값을 지정하는 원하는 IPC 객체를 제거 Linux System Programming
메시지 큐(Message Queue) (1) • 메시지 큐(Message Queue) • 프로세스간에 이산적인 데이터를 메시지 형태로 전송하는 통신 도구 • 파이프와 같이 FIFO 타입의 데이터 전송을 지원 • 메시지는 메시지와 바이트(byte)들의 모임으로 구성 • 메시지 유형은 정수값으로 여러가지 메시지 형태에 id를 부여하여 구별하기 위해 사용 • 바이트 모임은 전송하는 데이터를 의미하는 것으로 문자, 그림 또는 일련의 구조체 데이터 등을 전송하기 위햇 사용 • 관련 시스템 호출 함수 • msgget() – 메시지 큐를 생성 • msgsnd()/msgrcv() – 메시지 전송 및 수신 • msgctl() – 메시지 큐 제어 Linux System Programming
메시지 큐(Message Queue) (2) • 메시지 큐의 구조: • 메시지 큐의 상태 구조체 : msgid_ds • 메시지 큐 객체의 상태 정보를 저장하는 구조체 • 하나의 메시지 큐가 생성되면 하나의 msgid_ds 구조체가 생성 Linux System Programming
메시지 큐(Message Queue) (3) • 메시지 큐의 동작: • 전송 프로세스가 전송할 데이터를 메시지 형태로 만들어 메시지를 전송하면 전송된 메시지는 메시지 큐의 마지막에 연결된다 • 수신 프로세스는 메시지 큐에 존재하는 메시지를 선택적으로 수신할 수 있다. • 수신 프로세스에서는 메시지를 수신할 때에 다음의 수신 정책 중에 하나를 지정하여야 한다. • 메시지 큐에서 첫번째 메시지 • 메시지 큐에서 지정된 타입의 첫번째 메시지 • 메시지 큐에 있는 타입들의 범위들로 부터 첫번째 메시지 Linux System Programming
메시지 큐(Message Queue) (4) • 메시지 큐의 생성: msgget() • 메시지 큐 생성 시스템 호출 • 주어진 key를 갖는 메시지 큐가 존재하면 메시지 큐의 id를 반환하고, 그렇지 않으면 새롭게 메시지 큐를 생성하고 id를 반환 Linux System Programming
메시지 큐(Message Queue) (5) Linux System Programming
메시지 큐(Message Queue) (6) • 메시지 큐의 생성: msgget() • msgget() 시스템 호출의 flag 옵션 Linux System Programming
메시지 큐(Message Queue) (7) • 메시지 큐 구조체: msqid_ds Linux System Programming
메시지 큐(Message Queue) (8) • 메시지 큐 구조체 초기값 Linux System Programming
메시지 큐(Message Queue) (9) • 메시지 큐의 제어: msgctl() • 메시지 큐 제어 시스템 호출 • 메시지 큐의 상태를 질의하거나 상태 정보를 변경, 또는 메시지 큐를 제거하는 기능을 지원 Linux System Programming
메시지 큐(Message Queue) (10) • 메시지 큐의 제어: msgctl() • msgctl() 시스템 호출의 명령어 Linux System Programming
메시지 큐(Message Queue) (11) • msgctl() 시스템 호출의 사용 예 • 메시지 큐 관련 자료 구조 선언 • 메시지 큐의 제거 • 메시지 큐의 소유자 변경 #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msqid; struct msqid_ds ds; msgctl(msqid, IPC_RMID, (struct msqid_ds *)0); msgctl(msqid, IPC_STAT, &ds); ds.msg_perm.uid = 51; msgctl(msqid, IPC_SET, &ds); Linux System Programming
메시지 큐(Message Queue) (12) • msgctl() 시스템 호출의 사용 예 • 메시지 큐의 접근 허가 변경 • 메시지 큐의 메시지 크기 변경 msgctl(msqid, IPC_STAT, &ds); ds.msg_perm.mode = 0660; msgctl(msqid, IPC_SET, &ds); msgctl(msqid, IPC_STAT, &ds); ds.msg_qbytes = 5000; msgctl(msqid, IPC_SET, &ds); Linux System Programming
메시지 큐(Message Queue) (13) • 메시지 큐의 연산: msgsnd(), msgrcv() • 메시지 구조체 : • 메시지 유형은 전송되는 여러가지 유형의 메시지 형태를 분류하여 지정 • 메시지 텍스트는 전송하는 데이터를 저장 • 메시지 텍스트의 크기는 최소 0에서 최대 64 KB 이내이며, 묵시적으로 2048 바이트로 사용 #include <sys/msg.h> struct msgbuf { long mtype; /* 메시지 유형 */ char mtext[1]; /* 메지시 텍스트 */ } Linux System Programming
메시지 큐(Message Queue) (14) • 메시지 송신 시스템 호출 : msgsnd() Linux System Programming
메시지 큐(Message Queue) (15) • 메시지 송신 시스템 호출 : msgsnd() • msgsnd 시스템 호출에 의한 메시지 큐 구조체 변경 Linux System Programming
메시지 큐(Message Queue) (16) • 메시지 수신 시스템 호출 : msgrcv() Linux System Programming
메시지 큐(Message Queue) (17) • 메시지 수신 시스템 호출 : msgrcv() • msgrcv() 시스템 호출에서의 메시지 타입 지정 Linux System Programming
예제 프로그램 #1 (1) • 하나의 메시지를 전송하고 수신하는 프로그램 // file name : ex9-1a.c // #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct { long t; char a[60]; } x = {11L,"hello"}; main() { int mid; mid = msgget(11L,IPC_CREAT | 0666); msgsnd(mid,&x,strlen(x.a)+1,0); sleep(60); msgctl(mid,IPC_RMID,0); } Linux System Programming
예제 프로그램 #1 (2) // file name : ex9-1b.c // #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct { long t; char a[60]; } x ; main() { int mid,rtn; mid = msgget(11L,0); rtn=msgrcv(mid,&x,60,0L,0); printf("rtn=%d type=%d text=%s\n",rtn,x.t,x.a); } Linux System Programming
예제 프로그램 #2 (1) • 예제 프로그램 #1을 개선하여 여러 개의 메시지를 송수신하는 프로그램 // file name : ex9-2a.c // #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_SEND_SZ 30 #define DONE 99L main() { void perror(); key_t key; int mid; static struct { long mtype; char mtext[MAX_SEND_SZ]; } buf; Linux System Programming
예제 프로그램 #2 (2) static char *string[3] = { "hello", "how are you", "good-bye"}; int i,rtn; if((key= ftok(".",'a'))==-1) { perror("Can\'t form key"); exit(1); } mid = msgget(key,IPC_CREAT| 0660); if(mid == -1) { perror("Sender can not make msg queue!"); exit(2); } Linux System Programming
예제 프로그램 #2 (3) buf.mtype = 1L; for(i=0;i<3;i++) { strcpy(buf.mtext,string[i]); if(msgsnd(mid,&buf,strlen(buf.mtext)+1,0)==-1) { perror("Sender can not msgsnd!"); exit(3); } } rtn = msgrcv(mid,&buf,MAX_SEND_SZ,DONE,0); if(rtn == -1) { perror("Sender can not msgrcv"); exit(4); } msgctl(mid,IPC_RMID,0); } Linux System Programming
예제 프로그램 #2 (4) // file name : ex9-2b.c // #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_RECV_SZ 60 #define FIFO 0L #define ZERO_LEN 0 #define DONE 99L static struct { long mtype; char mtext[MAX_RECV_SZ]; } buf; key_t key; int mid; int rtn; Linux System Programming
예제 프로그램 #2 (5) int main(int argv,char *argc[]) { void perror(); if((key= ftok(".",'a'))==-1) { perror("Can\'t form key"); exit(1); } mid = msgget(key,0); if(mid == -1) { perror("Receiver can not access msg queue!"); exit(2); } while(1) { rtn = msgrcv(mid,&buf,MAX_RECV_SZ,FIFO,0); printf("rtn=%d buf.mtype=%ld buf.mtext=%s\n", rtn,buf.mtype,buf.mtext); if(!strcmp(buf.mtext,"good-bye")) break; } buf.mtype = DONE; msgsnd(mid,&buf,ZERO_LEN,0); exit(0); }
예제 프로그램 #3 (1) • 메시지 송신 프로그램가 키보드 입력을 메시지로 만들어 여러 개의 수신 프로그램에 전달하는 프로그램 • 송신 프로그램은 fork()/exec() 시스템 호출을 통하여 수신 프로세스를 생성하고, 수신 프로세스는 수신된 메시지를 표준 출력으로 출력하도록 한다. // file name : ex9-3a.c // #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_SZ 80 #define NCHILD 3 Linux System Programming
예제 프로그램 #3 (2) #define WAIT_SOLE_USE(MSGQID) { \ int still_active = NCHILD; \ int i; \ long s_pid; \ s_pid = getpid(); \ while(still_active) { for(i=0;i<NCHILD;i++) \ if(msgrcv(MSGQID,&buf,MAX_SZ,s_pid,IPC_NOWAIT) != -1) \ if(!strncmp(buf.mtext,"DONE",4)) still_active--; \ sleep(2); \ } \ } int main(void) { void perror(); key_t ftok(); int msgqid; struct { long mtype; char mtext[MAX_SZ]; } buf; Linux System Programming
예제 프로그램 #3 (3) int msg_length; static char qid_evar[40]; static char *envp[2] = { qid_evar }; int this_fork, child; long r_pid[NCHILD]; char child_name[20]; int eof = 0; if((msgqid = msgget(IPC_PRIVATE,IPC_CREAT | 0660)) == -1) { perror("Sender can't make message queue!"); exit(1); } sprintf(qid_evar,"MQID=%d",msgqid); for(child=0;child<NCHILD;child++) { this_fork = fork(); if(this_fork == -1) { perror("fork failed"); exit(2); } else if(this_fork == 0) { sprintf(child_name,"mwall_r%d",child); execle("ex9-3b",child_name,0,envp); perror("exec failed"); exit(3); } Linux System Programming
예제 프로그램 #3 (4) else r_pid[child] = (long) this_fork; } setbuf(stdout,(char *) 0); while(1) { fprintf(stdout, "Enter message to be sent to all receivers:"); if(gets(buf.mtext) == (char *) 0) { fprintf(stdout,"\n"); eof++; strcpy(buf.mtext,"EOF"); } msg_length = strlen(buf.mtext) +1; for(child=0;child<NCHILD;child++) { buf.mtype = r_pid[child]; if(msgsnd(msgqid,&buf,msg_length,0) == -1) { perror("Producer msgsnd error"); exit(4); } } if(eof) break; sleep(1); } Linux System Programming
예제 프로그램 #3 (5) WAIT_SOLE_USE(msgqid); msgctl(msgqid,IPC_RMID,0); exit(0); } Linux System Programming
예제 프로그램 #3 (6) // file name : ex9-3b.c // #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_SZ 80 int main(int argc, char *argv[]) { void perror(); char *getenv(); long pid; char *valuep; int msgqid; struct { long mtype; char mtext[MAX_SZ]; } buf; Linux System Programming
예제 프로그램 #3 (7) pid = (long) getpid(); if((valuep = getenv("MQID")) == NULL) { fprintf(stderr,"%s:can't get env MQID\n",argv[0]); exit(1); } else sscanf(valuep,"%d",&msgqid); while(1) { msgrcv(msgqid,&buf,MAX_SZ,pid,MSG_NOERROR); printf("%s received '%s'\n",argv[0],buf.mtext); if(!strcmp(buf.mtext,"EOF")) break; } buf.mtype = (long) getppid(); strcpy(buf.mtext,"DONE"); if(msgsnd(msgqid,&buf,strlen(buf.mtext),0) == -1) { fprintf(stderr,"%s:msgsnd error\n",argv[0]); exit(2); } exit(0); } Linux System Programming
세마포어(Semaphore) (1) • 세마포어(Semaphore) • 실행단위(프로세스 또는 쓰레드) 간의 동기화 도구 • 2개의 원자적 연산 P와 V가 정의되어 있는,정수값을 가지는 객체 • s : 세마포어 • P(s) : if ( s > 0 ) then s-- else 현재 프로세스는 대기한다; • V(s) : if ( 1개 이상의 프로세스가 대기중 ) then 1개 프로세스만 진행한다else s++; • 일상 생활에서의 ‘신호등’과 같은 동작을 수행 • 철도 교통을 통제하기 위한 깃발신호로부터 유래 Linux System Programming
세마포어(Semaphore) (2) • 세마포어(Semaphore) (계속) • 세마포어 연산 P & V 는 원자적 연산(atomic operation) • 하나의 프로세스가 P 또는 V 연산을 실행하는 도중에는 중지하지 않는다 • 어떤 프로세스가 P 또는 V 연산을 이용하여 세마포어에 접근하는 동안에는 다른 프로세스가 세마포어 값을 변경할 수 없다 • 세마포어의 활용 • 상호 배제(mutual exclusion) 문제 – 두 개 이상의 프로세스가 하나의 공유 자원을 접근할 때에 한 순간에 하나의 프로세스만 공유 자원을 접근할 수 있도록 보장함 • 실행 동기화 – 두 개 이상의 프로세스간에 실행 순서에 맞추어 실행됨을 보장함 Linux System Programming
세마포어(Semaphore) (3) • 세마포어 종류 : • 이진 세마포어(Binary Semaphore) • 0 또는 1의 정수 값만 가지는 세마포어 • P(s) 연산은 세마포어 s가 1일 때에 0으로 변경 • V(s) 연산은 세마포어 s가 0일 때에 1로 변경 • 하나의 자원에 대한 공유 및 동기화를 지원 • 계수형 세마포어(Counting Semaphore) • 범위에 제한이 없는 정수 값을 가지는 세마포어 • 일반적으로 언급하는 세마포어 • 다수의 공유 자원에 대해 여러 프로세스가 접근할 때에 상호 배제 및 동기화를 지원 Linux System Programming
세마포어(Semaphore) (4) • 세마포어 이용 - 공유 자원에 대한 상호 배제(Mutual Exclusion) • 여러 개의 프로세스가 하나의 자원을 공유하는 경우, 동시에 여러 프로세스가 자원을 접근하면 예상하지 못하는 문제가 발생함 • 예: 동시에 여러 프로그램이 프린터에 출력을 시도하는 경우 • 해결책 – 상호 배제 • 한 순간에 하나의 프로세스만 공유 자원을 접근함을 보장함 • 임계 영역(Critical Section) : 전체 프로그램 중에서 공유자원을 접근하는 프로그램 영역 • 한 순간에 임계 영역을 실행하는 프로세스는 하나만 존재하도록 보장함 • 세마포어를 이용하여 상호 배제를 구현 • 공유자원의 갯수에 따라 이진 세마포어 또는 계수형 세마포어를 사용 • 공유 자원에 대한 잠금과 풀기(lock & unlock) 기능을 지원 Linux System Programming
프로세스 P1 프로세스 P2 세마포어 s (초기값: 1) P(s) V(s) P(s) V(s) Critical Section Critical Section 공유 자원 세마포어(Semaphore) (5) • 세마포어 이용 - 공유 자원에 대한 상호 배제(Mutual Exclusion) Linux System Programming