슬라이드 1

Similar documents
고급 IPC 설비

Chap06(Interprocess Communication).PDF

메시지큐를이용한 IPC 프로그램구현과제보고서 1. 과제의목적 1 리눅스가지원하는프로세스간통신방식중다수의프로세스사이에구조화된데이터블럭, 즉메시지를전달하는데주로사용되는메시지큐방식에대하여무엇인지, 어떻게사용하는지공부한다. 2 공부한내용을점검하기위해기작성된 epda 프로세스관

제1장 Unix란 무엇인가?

<4D F736F F F696E74202D FBDC3BDBAC5DB56C0C720C7C1B7CEBCBCBDBAB0A320C5EBBDC5205BC8A3C8AF20B8F0B5E55D>

6주차.key

2009년 상반기 사업계획

고급 IPC 설비

Microsoft PowerPoint - UnixNetProg3rd_08_완.ppt [호환 모드]

운영체제 실습 - Introduction -

제1장 Unix란 무엇인가?

1장. 유닉스 시스템 프로그래밍 개요

제12장 파일 입출력

10.

Microsoft PowerPoint - 09-Pipe

chap7.key

Chapter #01 Subject

<4D F736F F F696E74202D20B8AEB4AABDBA20BFC0B7F920C3B3B8AEC7CFB1E22E BC8A3C8AF20B8F0B5E55D>

10주차.key

슬라이드 1

ABC 11장

The Pocket Guide to TCP/IP Sockets: C Version

좀비프로세스 2

vi 사용법

2009년 상반기 사업계획

슬라이드 1

< E20C6DFBFFEBEEE20C0DBBCBAC0BB20C0A7C7D12043BEF0BEEE20492E707074>

[ 마이크로프로세서 1] 2 주차 3 차시. 포인터와구조체 2 주차 3 차시포인터와구조체 학습목표 1. C 언어에서가장어려운포인터와구조체를설명할수있다. 2. Call By Value 와 Call By Reference 를구분할수있다. 학습내용 1 : 함수 (Functi

Microsoft PowerPoint - ch09_파이프 [호환 모드]

2009년 상반기 사업계획

Abstract View of System Components

/chroot/lib/ /chroot/etc/

11장 포인터

The Pocket Guide to TCP/IP Sockets: C Version

PowerPoint 프레젠테이션

Microsoft PowerPoint - chap13-입출력라이브러리.pptx

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

The Pocket Guide to TCP/IP Sockets: C Version

Sena Technologies, Inc. HelloDevice Super 1.1.0

슬라이드 1

<4D F736F F F696E74202D FB8DEB8F0B8AE20B8C5C7CE205BC8A3C8AF20B8F0B5E55D>

untitled

2009년 상반기 사업계획

제9장 프로세스 제어

03장.스택.key

Microsoft PowerPoint - [2009] 02.pptx

입학사정관제도

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

À©µµ³×Æ®¿÷ÇÁ·Î±×·¡¹Ö4Àå_ÃÖÁ¾

Microsoft Word - Network Programming_NewVersion_01_.docx

제1장 Unix란 무엇인가?

Microsoft PowerPoint - ch09 - 연결형리스트, Stack, Queue와 응용 pm0100

Microsoft PowerPoint - ch07 - 포인터 pm0415

untitled

이번장에서학습할내용 동적메모리란? malloc() 와 calloc() 연결리스트 파일을이용하면보다많은데이터를유용하고지속적으로사용및관리할수있습니다. 2

K&R2 Reference Manual 번역본

<4D F736F F F696E74202D FC7C1B7CEBCBCBDBA20BBFDBCBAB0FA20BDC7C7E0205BC8A3C8AF20B8F0B5E55D>

2009년 상반기 사업계획

Chapter 4. LISTS

PowerPoint 프레젠테이션

<322EBCF8C8AF28BFACBDC0B9AEC1A6292E687770>

슬라이드 1

슬라이드 1

Microsoft PowerPoint APUE(Intro).ppt

Poison null byte Excuse the ads! We need some help to keep our site up. List 1 Conditions 2 Exploit plan 2.1 chunksize(p)!= prev_size (next_chunk(p) 3

Microsoft PowerPoint - Lecture_Note_5.ppt [Compatibility Mode]

Microsoft PowerPoint - chap11-포인터의활용.pptx

본 강의에 들어가기 전

목차 포인터의개요 배열과포인터 포인터의구조 실무응용예제 C 2


1장. 유닉스 시스템 프로그래밍 개요

PowerPoint 프레젠테이션

Microsoft PowerPoint - 13 ¼ÒÄÏÀ» ÀÌ¿ëÇÑ Åë½Å 2.ppt

슬라이드 1

C++-¿Ïº®Çؼ³10Àå

리눅스 프로세스 관리

Microsoft PowerPoint - ch10 - 이진트리, AVL 트리, 트리 응용 pm0600

Microsoft PowerPoint - chap10-함수의활용.pptx

3. 다음장에나오는 sigprocmask 함수의설명을참고하여다음프로그램의출력물과그출력물이화면이표시되는시점을예측하세요. ( 힌트 : 각줄이표시되는시점은다음 4 가지중하나. (1) 프로그램수행직후, (2) kill 명령실행직후, (3) 15 #include <signal.

학습목차 2.1 다차원배열이란 차원배열의주소와값의참조

BMP 파일 처리

Microsoft PowerPoint - 3ÀÏ°_º¯¼ö¿Í »ó¼ö.ppt

Microsoft PowerPoint - Lecture_Note_7.ppt [Compatibility Mode]

Microsoft PowerPoint - 08-chap06-Queue.ppt

Microsoft PowerPoint - StallingsOS6e-Chap05.pptx

Microsoft PowerPoint - chap03-변수와데이터형.pptx

<4D F736F F F696E74202D20C1A63137C0E520B5BFC0FBB8DEB8F0B8AEBFCD20BFACB0E1B8AEBDBAC6AE>

PowerPoint 프레젠테이션

chap 5: Trees

Microsoft PowerPoint - 제11장 포인터(강의)

강의10

비트와바이트 비트와바이트 비트 (Bit) : 2진수값하나 (0 또는 1) 를저장할수있는최소메모리공간 1비트 2비트 3비트... n비트 2^1 = 2개 2^2 = 4개 2^3 = 8개... 2^n 개 1 바이트는 8 비트 2 2

untitled

Microsoft PowerPoint - chap12 [호환 모드]

untitled

<4D F736F F F696E74202D20BBB7BBB7C7D15F FBEDFB0A3B1B3C0B05FC1A638C0CFC2F72E BC8A3C8AF20B8F0B5E55D>

Microsoft PowerPoint - 08-Queue.ppt

歯9장.PDF

Transcription:

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)

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

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

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

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

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

IPC(Inter-Process Communication) (6) IPC 도구식별자 : IPC key 변환시스템호출 ftok(file_to_key) Linux System Programming 9

IPC(Inter-Process Communication) (7) IPC 도구의상태자료구조 : 생성된 IPC 객체에대한상태정보를저장하는구조체 IPC 도구유형별로별도의상태구조체를지원하나다음의접근허가구조를공통으로포함한다 IPC 도구의접근허가구조 : struct ipc_perm 파일의접근허가와유사한기능을지원 접근모드에서실행모드는무의미함 Linux System Programming 10

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

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

Message Queue

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

예제프로그램 #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 31

예제프로그램 #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 32

예제프로그램 #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 33

예제프로그램 #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 34

예제프로그램 #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 35

예제프로그램 #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 36

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

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

예제프로그램 #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 39

예제프로그램 #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 40

예제프로그램 #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 41

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

// file name : ex9-3b.c // #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #define MAX_SZ 80 예제프로그램 #3 (6) int main(int argc, char *argv[]) { void perror(); char *getenv(); long pid; char *valuep; int msgqid; struct { buf; long mtype; char mtext[max_sz]; Linux System Programming 43

예제프로그램 #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 44

Semaphore

세마포어 (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 46

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

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

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

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

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

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

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

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

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

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

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

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

세마포어 (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, Linux ANY); System Programming 59

세마포어 (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 60

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

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

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

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

예제프로그램 #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 65

예제프로그램 #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 66

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

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

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

예제프로그램 #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; if(semop(semid, operation, 2) == -1) { sprintf(errmsg,"%s - RELEASE", argv[0]); perror(errmsg); exit(7); exit(0); 70

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

예제프로그램 #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 72

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

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

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

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

Shared Memory

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

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

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

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

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

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

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

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

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

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

// 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" 예제프로그램 #7 (2) class_t class = { "1001", "120186", "C Language for Programmers", 15 ; #define NCHILD 3 int child[nchild]; char int char char void *shm_ptr, *shmat(); semid, shmid; ascsemid[10], ascshmid[10]; pname[14]; rpterror(); int main(int argc, char *argv[]) { Linux System Programming 88 int i;

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

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

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

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

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

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

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

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

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

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

예제프로그램 #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. */ 99

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

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