Presentation is loading. Please wait.

Presentation is loading. Please wait.

Task 통신 및 동기화 : Message Queue, Semaphore Shared Memory

Similar presentations


Presentation on theme: "Task 통신 및 동기화 : Message Queue, Semaphore Shared Memory"— Presentation transcript:

1 Task 통신 및 동기화 : Message Queue, Semaphore Shared Memory
Chapter #12

2 강의 목차 IPC(Inter-Process Communication) 메시지 큐(Message Queue)
세마포어(Semaphore) 공유 메모리(Shared Memory) Unix System Programming Unix System Programming 2

3 IPC(Inter-Process Communication)

4 IPC(Inter-Process Communication) (1)
프로세스 통신 도구(IPC Facilites) : 비동기적으로 동작하는 프로세스간의 통신을 위하여 운영체제가 제공하는 도구 종류: Signal(신호) Pipe(파이프) Message Queue(메시지 큐) Semaphore(세마포어) Shared Memory(공유 메모리) Socket(소켓) 동일한 플랫폼 상에서 유사하게 구현되어 ICP 도구로 별도 분류하기도 함 Linux System Programming

5 IPC(Inter-Process Communication) (2)
프로세스 통신 도구 (IPC Facilites) : 세마포어(Semaphore) 프로세스 동기화와 자원 관리에 사용 프로세스간의 상호배제 문제 해결에 사용 공유 메모리(Shared Memory) 가장 빠른 프로세스 통신 도구 하나 이상의 프로세스에 부착하여 서로 공유하여 접근 가능 프로세스간의 공유 메모리 접근을 위해 동기화가 필요 메시지 큐(Message Queue) 프로세스들간에 이산적인 양의 데이터 송수신을 위해 사용 전송할 데이터를 메시지 형태로 생성하여 전달하고 메시지 수신을 통해 데이터 수신이 가능 인터넷 메일 서비스와 개념이 유사 Linux System Programming

6 IPC(Inter-Process Communication) (3)
get ctl op 세마포어 semget semctl semop 공유 메모리 shmget shmctl shmop(shmat, shmdt) 메시지큐 msgget msgctl msgop(msgsnd, msgrcv) 기 능 IPC 도구의 생성 및 참조 기능 제공 소유자 및 접근 허가 변경 등의 기능 제공 IPC 도구의 연산(송수신 제어 등) 기능 제공 Linux System Programming

7 IPC(Inter-Process Communication) (4)
get 시스템 호출 파일 열기 시스템 호출 open과 유사 새롭게 통신 도구를 생성하거나 이미 생성된 통신 도구에 대한 id를 반환하여 접근 가능하게 함 반환된 id는 파일 디스크립터와 비슷하게 동작 접근 허가 또한 파일 접근 허가와 비슷하게 규정 ctl 시스템 호출 통신 도구에 관한 상태 정보 읽기 몇몇 상태 정보(소유자, 그룹, 접근 허가 등)에 대한 변경 통신 도구의 제거 기능 op 시스템 호출 프로세스간의 데이터 전송을 실행 파일 시스템 호출 read/write와 유사 Shmat는 파일의 open과 유사하고, shmdt는 파일의 close와 유사 Linux System Programming

8 IPC(Inter-Process Communication) (5)
IPC 도구 식별자 – IPC key 파일을 식별하기 위해 파일 이름을 사용하듯이 IPC 객체를 식별하기 위해 사용하는 정수형 숫자 프로세스들은 IPC key를 이용하여 IPC 자원을 공유 자료형: key_t (<sys/types.h>에 정의) IPC key 변환 시스템 호출 – ftok(file_to_key) IPC 도구의 공유를 편리하게 지원하기 위해 파일 경로명과 식별자를 IPC 도구에 부여하고, 이를 IPC key 값으로 변환하는 시스템 호출 char device Inode # of file key_t Linux System Programming

9 IPC(Inter-Process Communication) (6)
IPC key 변환 시스템 호출 – ftok(file_to_key) Linux System Programming

10 IPC(Inter-Process Communication) (7)
IPC 도구의 접근 허가 구조: struct ipc_perm 파일의 접근 허가와 유사한 기능을 지원 접근 모드에서 실행 모드는 무의미함 Linux System Programming

11 IPC(Inter-Process Communication) (8)
IPC 도구 유형별로 생성된 IPC 객체를 관리하기 위해 운영체제가 유지하는 테이블 IPC 도구 유형별로 각각의 테이블을 유지 파일 테이블과 유사한 개념 Linux System Programming

12 IPC(Inter-Process Communication) (9)
ipcs 명령 현재 사용중인 IPC 도구들의 상태(status)를 보여주는 명령 IPC 타입, 사용자 ID, key 값 그리고 접근 허가 등을 볼 수 있음 옵션을 사용하여 지정된 유형의 IPC 도구 상태 정보만을 접근 가능 -q : 메시지 큐, -m : 공유 메모리, -s : 세마포어 ipcrm 명령 IPC 객체를 제거하는 명령 IPC 도구 유형 및 key 값을 지정하는 원하는 IPC 객체를 제거 Linux System Programming

13 Message Queue

14 메시지 큐(Message Queue) (1)
프로세스간에 이산적인 데이터를 메시지 형태로 전송하는 통신 도구 파이프와 같이 FIFO 타입의 데이터 전송을 지원 메시지는 메시지와 바이트(byte)들의 모임으로 구성 메시지 유형은 정수값으로 여러가지 메시지 형태에 id를 부여하여 구별하기 위해 사용 바이트 모임은 전송하는 데이터를 의미하는 것으로 문자, 그림 또는 일련의 구조체 데이터 등을 전송하기 위햇 사용 관련 시스템 호출 함수 msgget() – 메시지 큐를 생성 msgsnd()/msgrcv() – 메시지 전송 및 수신 msgctl() – 메시지 큐 제어 Linux System Programming

15 메시지 큐(Message Queue) (2)
메시지 큐의 구조: 메시지 큐의 상태 구조체 : msgid_ds 메시지 큐 객체의 상태 정보를 저장하는 구조체 하나의 메시지 큐가 생성되면 하나의 msgid_ds 구조체가 생성 Linux System Programming

16 메시지 큐(Message Queue) (3)
메시지 큐의 동작: 전송 프로세스가 전송할 데이터를 메시지 형태로 만들어 메시지를 전송하면 전송된 메시지는 메시지 큐의 마지막에 연결된다 수신 프로세스는 메시지 큐에 존재하는 메시지를 선택적으로 수신할 수 있다. 수신 프로세스에서는 메시지를 수신할 때에 다음의 수신 정책 중에 하나를 지정하여야 한다. 메시지 큐에서 첫번째 메시지 메시지 큐에서 지정된 타입의 첫번째 메시지 메시지 큐에 있는 타입들의 범위들로 부터 첫번째 메시지 Linux System Programming

17 메시지 큐(Message Queue) (4)
메시지 큐의 생성: msgget() 메시지 큐 생성 시스템 호출 주어진 key를 갖는 메시지 큐가 존재하면 메시지 큐의 id를 반환하고, 그렇지 않으면 새롭게 메시지 큐를 생성하고 id를 반환 Linux System Programming

18 메시지 큐(Message Queue) (5)
Linux System Programming

19 메시지 큐(Message Queue) (6)
메시지 큐의 생성: msgget() msgget() 시스템 호출의 flag 옵션 Linux System Programming

20 메시지 큐(Message Queue) (7)
메시지 큐 구조체: msqid_ds Linux System Programming

21 메시지 큐(Message Queue) (8)
메시지 큐 구조체 초기값 Linux System Programming

22 메시지 큐(Message Queue) (9)
메시지 큐의 제어: msgctl() 메시지 큐 제어 시스템 호출 메시지 큐의 상태를 질의하거나 상태 정보를 변경, 또는 메시지 큐를 제거하는 기능을 지원 Linux System Programming

23 메시지 큐(Message Queue) (10)
메시지 큐의 제어: msgctl() msgctl() 시스템 호출의 명령어 Linux System Programming

24 메시지 큐(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

25 메시지 큐(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

26 메시지 큐(Message Queue) (13)
메시지 큐의 연산: msgsnd(), msgrcv() 메시지 구조체 : 메시지 유형은 전송되는 여러가지 유형의 메시지 형태를 분류하여 지정 메시지 텍스트는 전송하는 데이터를 저장 메시지 텍스트의 크기는 최소 0에서 최대 64 KB 이내이며, 묵시적으로 2048 바이트로 사용 #include <sys/msg.h> struct msgbuf { long mtype; /* 메시지 유형 */ char mtext[1]; /* 메지시 텍스트 */ } Linux System Programming

27 메시지 큐(Message Queue) (14)
메시지 송신 시스템 호출 : msgsnd() Linux System Programming

28 메시지 큐(Message Queue) (15)
메시지 송신 시스템 호출 : msgsnd() msgsnd 시스템 호출에 의한 메시지 큐 구조체 변경 Linux System Programming

29 메시지 큐(Message Queue) (16)
메시지 수신 시스템 호출 : msgrcv() Linux System Programming

30 메시지 큐(Message Queue) (17)
메시지 수신 시스템 호출 : msgrcv() msgrcv() 시스템 호출에서의 메시지 타입 지정 Linux System Programming

31 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

32 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

33 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

34 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

35 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

36 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

37 예제 프로그램 #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);

38 Linux System Programming
예제 프로그램 #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

39 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

40 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

41 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

42 Linux System Programming
예제 프로그램 #3 (5) WAIT_SOLE_USE(msgqid); msgctl(msgqid,IPC_RMID,0); exit(0); } Linux System Programming

43 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

44 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

45 Semaphore

46 Linux System Programming
세마포어(Semaphore) (1) 세마포어(Semaphore) 실행단위(프로세스 또는 쓰레드) 간의 동기화 도구 2개의 원자적 연산 P와 V가 정의되어 있는,정수값을 가지는 객체 s : 세마포어 P(s) : if ( s > 0 ) then s-- else 현재 프로세스는 대기한다; V(s) : if ( 1개 이상의 프로세스가 대기중 ) then   개 프로세스만 진행한다 else s++; 일상 생활에서의 ‘신호등’과 같은 동작을 수행 철도 교통을 통제하기 위한 깃발신호로부터 유래 Linux System Programming

47 Linux System Programming
세마포어(Semaphore) (2) 세마포어(Semaphore) (계속) 세마포어 연산 P & V 는 원자적 연산(atomic operation) 하나의 프로세스가 P 또는 V 연산을 실행하는 도중에는 중지하지 않는다 어떤 프로세스가 P 또는 V 연산을 이용하여 세마포어에 접근하는 동안에는 다른 프로세스가 세마포어 값을 변경할 수 없다 세마포어의 활용 상호 배제(mutual exclusion) 문제 – 두 개 이상의 프로세스가 하나의 공유 자원을 접근할 때에 한 순간에 하나의 프로세스만 공유 자원을 접근할 수 있도록 보장함 실행 동기화 – 두 개 이상의 프로세스간에 실행 순서에 맞추어 실행됨을 보장함 Linux System Programming

48 Linux System Programming
세마포어(Semaphore) (3) 세마포어 종류 : 이진 세마포어(Binary Semaphore) 0 또는 1의 정수 값만 가지는 세마포어 P(s) 연산은 세마포어 s가 1일 때에 0으로 변경 V(s) 연산은 세마포어 s가 0일 때에 1로 변경 하나의 자원에 대한 공유 및 동기화를 지원 계수형 세마포어(Counting Semaphore) 범위에 제한이 없는 정수 값을 가지는 세마포어 일반적으로 언급하는 세마포어 다수의 공유 자원에 대해 여러 프로세스가 접근할 때에 상호 배제 및 동기화를 지원 Linux System Programming

49 Linux System Programming
세마포어(Semaphore) (4) 세마포어 이용 - 공유 자원에 대한 상호 배제(Mutual Exclusion) 여러 개의 프로세스가 하나의 자원을 공유하는 경우, 동시에 여러 프로세스가 자원을 접근하면 예상하지 못하는 문제가 발생함 예: 동시에 여러 프로그램이 프린터에 출력을 시도하는 경우 해결책 – 상호 배제 한 순간에 하나의 프로세스만 공유 자원을 접근함을 보장함 임계 영역(Critical Section) : 전체 프로그램 중에서 공유자원을 접근하는 프로그램 영역 한 순간에 임계 영역을 실행하는 프로세스는 하나만 존재하도록 보장함 세마포어를 이용하여 상호 배제를 구현 공유자원의 갯수에 따라 이진 세마포어 또는 계수형 세마포어를 사용 공유 자원에 대한 잠금과 풀기(lock & unlock) 기능을 지원 Linux System Programming

50 Linux System Programming
세마포어(Semaphore) (5) 세마포어 이용 - 공유 자원에 대한 상호 배제(Mutual Exclusion) 프로세스 P1 프로세스 P2 세마포어 s (초기값: 1) P(s) P(s) Critical Section 공유 자원 Critical Section V(s) V(s) Linux System Programming

51 Linux System Programming
세마포어(Semaphore) (6) 세마포어 이용 - 프로세스간의 실행 동기화(Synchronization) 하나의 프로그램이 여러 개의 프로세스로 이루어지는 경우, 프로세스간의 종속성에 의해 실행 순서가 정해지며, 반드시 실행 순서에 의해 동작하여함 예: 하나의 프로세스가 다른 프로세스가 제공하는 데이터를 받아 동작하는 경우 해결책 – 프로세스 실행 동기화 프로세서 P1가 T1 문장을 실행한 후에 프로세스 P2가 T2 문장을 실행하여야 하는 경우 프로세스 P2는 T2 문자을 실행하기 전에 프로세스 P1이 T1 문장을 실행하여는지를 검사 프로세스 P1이 T1 문장을 실행하였으면 바로 T2 문장을 실행 프로세스 P1이 T2 문장을 실행하지 않았으면 실행할 때까지 대기 세마포어를 이용하여 동기화를 지원함 대개의 경우 이진 세마포어를 사용 Linux System Programming

52 Linux System Programming
세마포어(Semaphore) (7) 세마포어 이용 - 프로세스간의 실행 동기화(Synchronization) 프로세스 P1 T1: ----- 프로세스 P2 T2: ----- 세마포어 s (초기값: 0) V(s) P(s) Linux System Programming

53 Linux System Programming
세마포어(Semaphore) (8) 세마포어의 생성: semget() Linux System Programming

54 Linux System Programming
세마포어(Semaphore) (9) 세마포어의 생성: semget() Linux System Programming

55 Linux System Programming
세마포어(Semaphore) (10) 세마포어의 생성: semget() semget() 시스템 호출의 동작 세마포어 구조체 초기화: Linux System Programming

56 Linux System Programming
세마포어(Semaphore) (11) 세마포어의 제어: semctl() 세마포어 제어 연산 세마포어의 집합 안에 개별적인 세마포어나 모든 세마포어에 대해 세마포어 값을 읽어오거나 새로운 값을 설정 세마포어 집합의 상태 정보을 읽어오거나 변경 세마포어에서 대기중인 프로세스의 수를 결정 마지막으로 세마포어를 연산한 프로세스를 결정 세마포어를 제거 semctl ()시스템 호출을 통해 상기의 세마포어 제어 연산을 실행 Linux System Programming

57 Linux System Programming
세마포어(Semaphore) (12) 세마포어의 제어: semctl() Linux System Programming

58 Linux System Programming
세마포어(Semaphore) (13) 세마포어의 제어: semctl() semctl() 시스템 호출의 명령어 및 반환값 Linux System Programming

59 Linux System Programming
세마포어(Semaphore) (14) 세마포어의 제어: semctl() 세마포어 생성 세마포어 집합에서 하나의 세마포어를 초기화 세마포어 집합에서 하나의 세마포어 값 읽기 #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #define ANY 0 int semid, rtn; struct semid_ds semds; ushort us[5], init_us[5] = {0, 6, 7, 1, 4}; semid = semget(key, 5, IPC_CREAT|0666); semctl(semid, 2, SETVAL, 7); // GETCNT, GETZCNT, GETPID도 같은 형태로 사용 semctl(semid, 2, GETVAL, ANY); Linux System Programming

60 Linux System Programming
세마포어(Semaphore) (15) 세마포어의 제어: semctl() 세마포어 집합 내의 모든 세마포어의 값을 초기화 세마포어 집합 내의 모든 세마포어의 값 읽기 세마포어의 소유자 변경 세마포어 집합 제거 semctl(semid, ANY, SETALL, init_us); semctl(semid, ANY, GETALL, us); // 접근 허가 모드 변경에도 같은 형태로 사용 semctl(semid, ANY, IPC_STAT, &semds); semds.sem_perm.uid = 51; semctl(semid, ANY, IPC_SET, &ds); semctl(semid, ANY, IPC_RMID, ANY); Linux System Programming

61 Linux System Programming
세마포어(Semaphore) (16) 세마포어의 연산: semop() 세마포어의 값을 증가시키거나 감소시키는 연산을 수행 Linux System Programming

62 Linux System Programming
세마포어(Semaphore) (17) Linux System Programming

63 Linux System Programming
세마포어(Semaphore) (18) Linux System Programming

64 예제 프로그램 #4 (1) 세마포어를 이용하여 공유 자원에 대한 접근을 제어하는 프로그램 공유 자원은 표준 출력
// file name : ex10-1.c // #include <sys/ipc.h> #include <sys/sem.h> #include <stdio.h> #define DUMMY 0 #define COUNT 4 int main(int argc, char *argv[]) { key_t ipckey; /* modified */ int semid, semget(),semctl(),semop(); int pid,getpid(); int creator,i; static struct sembuf lock = {0,-1,SEM_UNDO}; static struct sembuf unlock = {0, 1,SEM_UNDO}; setbuf(stdout,(char *) NULL);

65 Linux System Programming
예제 프로그램 #4 (2) ipckey = ftok(argv[0],'s'); if((semid = semget(ipckey,1,IPC_CREAT | IPC_EXCL | 0666)) != -1) { creator = 1; } else { if((semid = semget(ipckey,1,0)) == -1) { perror(argv[0]); exit(1); creator = 0; if(creator) { if(semctl(semid,0,SETVAL,1) == -1) { perror(argv[0]); exit(2); pid = getpid(); for(i=0;i<COUNT;i++){ if(semop(semid,&lock,1) == -1) { perror(argv[0]); exit(3); printf("\t[%d]locking\t",pid); sleep(1); printf("[%d] unlocking\n",pid); Linux System Programming

66 Linux System Programming
예제 프로그램 #4 (3) if (semop(semid,&unlock,1) == -1) { perror(argv[0]); exit(4); } if (creator) { sleep(5); if(semctl(semid,DUMMY,IPC_RMID,DUMMY) == -1) { perror(argv[0]); exit(5); Linux System Programming

67 예제 프로그램 #5 (1) 다음 그림과 세 개의 세마포어를 갖는 세마포어 집합을 이용하여 프린터 자원을 관리하는 프로그램
첫번째 세마포어는 두 개의 프린터 모두를 관리하는 계수형 세마포어 두번째 및 세번째 세마포어는 각각 프린터1과 프린터2를 관리하는 세마포어 프린터는 단말기 장치를 PRINTER1으로, 정규 파일을 PRINTER2로 환경 변수를 정의하여 시뮬레이션한다

68 예제 프로그램 #5 (2) #include <fcntl.h> #include <sys/types.h>
#include <sys/ipc.h> #include <sys/sem.h> #include <stdio.h> #include "ex10-2.h" #define DUMMY 0 #define NUMPR 2 #define ACQUIRE -1 #define RELEASE 1 int main(int argc,char *argv[]) { char *getenv(), *printer[NUMPR], buf[BUFSIZ]; key_t ipckey; /* modified */ int semid, semget(), semctl(), semop(); ushort initial[NUMPR +1]; int i, prntnum, creator, getpid(); int n, fdin, fdout; struct sembuf operation[2]; char errmsg[30]; if((printer[1] = getenv("PRINTER1")) == (char *) NULL || (printer[2] = getenv("PRINTER2")) == (char *) NULL) { printf("missing printer assignment\n"); exit(1); }

69 예제 프로그램 #5 (3) if(strncmp(argv[0],"line",4) ==0) prntnum = 1;
else if(strncmp(argv[0],"lase",4) ==0) prntnum =2; else prntnum = getpid() % NUMPR +1; ipckey = ftok(argv[0], 's'); if((semid = semget(ipckey,NUMPR +1,IPC_CREAT| IPC_EXCL| 0666)) != -1) { creator = 1; } else { if((semid = semget(ipckey, NUMPR +1, 0666)) == -1) { sprintf(errmsg, "%s - semget", argv[0]); perror(errmsg); exit(2); } if(creator) { /* initialize semaphore set */ initial[0] = NUMPR; for(i=1; i<= NUMPR; i++) initial[i] = 1; if(semctl(semid, DUMMY, SETALL, initial) == -1) { sprintf(errmsg,"%s -SETALL", argv[0]); perror(errmsg); exit(3); operation[1].sem_num = prntnum; operation[1].sem_op = ACQUIRE; operation[1].sem_flg = SEM_UNDO; operation[0].sem_num = 0; operation[0].sem_op = ACQUIRE; operation[0].sem_flg = SEM_UNDO;

70 예제 프로그램 #5 (4) if(semop(semid, operation, 2) == -1) {
sprintf(errmsg,"%s - ACQUIRE", argv[0]); perror(errmsg); exit(4); } if((fdin = open(argv[1], O_RDONLY)) == -1) { sprintf(errmsg,"%s - %s", argv[0], argv[1]); perror(errmsg); exit(5); if((fdout = open(printer[prntnum], O_CREAT| O_WRONLY)) == -1) { sprintf(errmsg,"%s - %s", argv[0], printer[prntnum]); perror(errmsg); exit(6); while((n= read(fdin, buf, BUFSIZ)) > 0) write(fdout, buf, n); operation[1].sem_op = RELEASE; operation[0].sem_op = RELEASE; sprintf(errmsg,"%s - RELEASE", argv[0]); perror(errmsg); exit(7); exit(0);

71 예제 프로그램 #6 (1) 다음 그림과 같은 생산 라인을 시뮬레이션하는 프로그램
각 공정은 다중 프로세스를 생성하고 이들의 생산 순서와 소비 시간을 세마포어와 프로세스 수면(sleep)을 이용하여 시뮬레이션한다

72 예제 프로그램 #6 (2) // // header file name : ex10-3.h #define NWIDGETS 5
#define PARTA 0 #define PARTB 1 #define PARTC 2 #define SUB1 3 #define HOLDER 0

73 예제 프로그램 #6 (3) // // source file name : ex10-3a.c
#include <signal.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include "ex10-3.h" int semprodn; void endsim(); int main(int argc, char *argv[]) { int widget; int pgrp; char asc_prod_key[20]; static struct sembuf partc_sub1[2] = { { PARTC, -1, SEM_UNDO}, { SUB1, -1, SEM_UNDO} }; if((semprodn=semget(IPC_PRIVATE,4,IPC_CREAT | 0640)) == -1) printf("Can't get production line semaphore set\n"); exit(1); }

74 예제 프로그램 #6 (4) signal(SIGINT, endsim);
sprintf(asc_prod_key,"%d", semprodn); if( fork() == 0) execl("ex10-3b","a", asc_prod_key, (char *)0); if( fork() == 0) execl("ex10-3b","b", asc_prod_key, (char *)0); if( fork() == 0) execl("ex10-3b","c", asc_prod_key, (char *)0); if( fork() == 0) execl("ex10-3c","ex10-3c", asc_prod_key, (char *)0); for(widget=1; widget < NWIDGETS; widget++) { semop(semprodn, partc_sub1, 2); printf("%s: ready to make widget #%d\n", argv[0], widget); } endsim(); void endsim() { semctl(semprodn, 0,IPC_RMID, 0); signal(SIGTERM, SIG_IGN); kill(0, SIGTERM); exit(0);

75 예제 프로그램 #6 (5) // // source file name : ex10-3b.c
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include "ex10-3.h" int main(int argc, char *argv[]) { int semprodn, index; int unit = 0; static struct sembuf parti = { HOLDER, 1, SEM_UNDO }; static int prodtimeabc[3] = {2,3,4}; semprodn = atoi( argv[1] ); index = argv[0][0]- 'a'; /* argv[0] == [abc] */ parti.sem_num = index; while(1) { semop(semprodn, &parti, 1); printf("%s: producing unit #%d\n", argv[0], ++unit); sleep(prodtimeabc[index]); }

76 예제 프로그램 #6 (6) // // source file name : ex10-3c.c
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include "ex10-3.h" int main(int argc, char *argv[]) { int semprodn; int unit = 0; static struct sembuf part_ab[2] = { {PARTA, -1, SEM_UNDO }, {PARTB, -1, SEM_UNDO } }; static struct sembuf sub1 = { SUB1, 1, SEM_UNDO }; semprodn = atoi( argv[1] ); while(1) { semop(semprodn, part_ab, 2); semop(semprodn, &sub1, 1); printf("%s: producing sub-assembly #%d\n", argv[0], ++unit); }

77 Shared Memory

78 공유메모리(Shared Memory) (1)
두 개이상의 프로세스가 실제 메모리의 일부를 공유하여 통신할 수 있는 IPC 도구 통신하려는 프로세스는 우선 공유 메모리를 할당받는다 프로세스는 할당된 공유 메모리를 자신의 가상주소공간 일부에 붙여(attach) 메모리에 데이터를 읽고 쓰는 것가 동일한 방법으로 필요한 데이터를 읽거나 전송하려는 데이터를 기록하여 상호 통신한다 프로세스간의 통신이 종료되면 공유 메모리를 가상주소공간에서 떼어내고(detach) 공유 메모리를 해제한다 IPC 도구 중에서 가장 효율적 시스템 간의 이식성이 낮음 프로세스간의 메모리 공유를 위해 별도의 하드웨어 지원이 필요 공유 메모리를 사용한 프로그램을 하드웨어 지원이 없는 시스템에서는 사용불가 Linux System Programming

79 공유메모리(Shared Memory) (2)
공유 메모리 시스템 호출 : shmget – 공유 메모리를 새롭게 할당하거나 할당된 공유 메모리의 핸들을 반환한다 shmctl – 공유 메모리와 관련된 상태 변수값을 변경하거나 공유 메모리를 제거한다 shmat – 공유 메모리를 프로세스의 가상주소공간에 논리적으로 부착(attach)한다 shmdt – 프로세스의 가상주소공간으로부터 공유 메모리를 분리한다 Linux System Programming

80 공유메모리(Shared Memory) (3)
공유 메모리 시스템 호출 : 공유메모리 shmget() 프로세스 P1 프로세스 P2 가상주소: 10000 shmat() 가상주소: 20000 shmat() shmdt() shmdt() shmctl() Linux System Programming

81 공유메모리(Shared Memory) (4)
공유 메모리의 생성: shmget() Linux System Programming

82 공유메모리(Shared Memory) (5)
공유 메모리의 생성: shmget() 공유 메모리 구조체 Linux System Programming

83 공유메모리(Shared Memory) (6)
공유 메모리의 생성: shmget() 공유 메모리 구조체의 초기화 Linux System Programming

84 공유메모리(Shared Memory) (7)
공유 메모리의 제어: shmctl() Linux System Programming

85 공유메모리(Shared Memory) (8)
공유 메모리의 제어: shmctl() shmctl() 시스템 호출의 명령어 Linux System Programming

86 공유메모리(Shared Memory) (9)
공유 메모리의 연산: shmat() / shmdt() Linux System Programming

87 예제 프로그램 #7 (1) 학원 강좌 예약 시스템 프로그램
부모 프로세스는 강좌 예약 정보를 갖는 공유 메모리을 할당하고, 공유 메모리에 대한 상호배제를 위한 세마포어를 생성한다 자식 프로세스을 생성하여 강좌 예약을 수행하는데, 자식 프로세스는 주기적으로 강좌 예약을 수행하도록 시뮬레이션하며, 더 이상 예약할 좌석(seat)가 없으면 종료한다 부모 프로세스는 모든 자식 프로세스가 종료할 때까지 기다렸다가 세마포어와 공유 메모리를 제거하고 종료한다 // // 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;

88 Linux System Programming
예제 프로그램 #7 (2) // 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

89 예제 프로그램 #7 (3) 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);

90 예제 프로그램 #7 (4) 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);

91 예제 프로그램 #7 (5) void rpterror(char *string) { char errline[50];
sprintf(errline,"%s %s",string, pname); perror(errline); }

92 예제 프로그램 #7 (6) // 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);

93 예제 프로그램 #7 (7) 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);

94 예제 프로그램 #7 (8) 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);

95 예제 프로그램 #8 (1) 세마포어와 공유 메모리를 이용하여 버퍼의 자료를 생산하고 소비하는 생산자/소비자(producer/consumer) 프로그램 생산자는 공유 메모리를 할당하여 버퍼를 설정한다 생산자와 소비자 사이에 버퍼 접근을 위한 동기화를 위해 2 개의 세마포어를 생성하여 사용한다 버퍼 쓰기 동기화(consumed 동기화) - 생산자는 소비자가 버퍼의 자료를 읽고 간 후에 새로운 자료를 버퍼에 쓴다 버퍼 읽기 동기화(produced 동기화) - 소비자는 생산자가 버퍼에 새로운 자료를 쓴 후에 자료를 읽어간다

96 예제 프로그램 #8 (2) // 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();

97 예제 프로그램 #8 (3) /* 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);

98 예제 프로그램 #8 (4) 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);

99 예제 프로그램 #8 (5) // 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.

100 예제 프로그램 #8 (6) 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);

101 예제 프로그램 #8 (7) 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);


Download ppt "Task 통신 및 동기화 : Message Queue, Semaphore Shared Memory"

Similar presentations


Ads by Google