task 통신 및 동기화 : message queue, semaphore shared memory

101
Task Task 통통 통 통통통 통통 통 통통통 : : Message Queue, Semaphore Message Queue, Semaphore Shared Memory Shared Memory Chapter #12

Upload: ewa

Post on 15-Jan-2016

256 views

Category:

Documents


0 download

DESCRIPTION

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 도구로 별도 분류하기도 함. - PowerPoint PPT Presentation

TRANSCRIPT

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

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

Shared MemoryShared Memory

Chapter #12

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

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

Unix System Programming 2Unix System Programming 2

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

IPC(Inter-Process IPC(Inter-Process Communication)Communication)

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

IPC(Inter-Process Communication) (1)

프로세스 통신 도구 (IPC Facilites) : 비동기적으로 동작하는 프로세스간의 통신을 위하여

운영체제가 제공하는 도구 종류 :

Signal( 신호 ) Pipe( 파이프 ) Message Queue( 메시지 큐 ) Semaphore( 세마포어 ) Shared Memory( 공유 메모리 ) Socket( 소켓 )

Linux System Programming 4

동일한 플랫폼 상에서 유사하게 구현되어 ICP 도구로 별도

분류하기도 함

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

IPC(Inter-Process Communication) (2)

프로세스 통신 도구 (IPC Facilites) : 세마포어 (Semaphore)

프로세스 동기화와 자원 관리에 사용 프로세스간의 상호배제 문제 해결에 사용

공유 메모리 (Shared Memory) 가장 빠른 프로세스 통신 도구 하나 이상의 프로세스에 부착하여 서로 공유하여 접근 가능 프로세스간의 공유 메모리 접근을 위해 동기화가 필요

메시지 큐 (Message Queue) 프로세스들간에 이산적인 양의 데이터 송수신을 위해 사용 전송할 데이터를 메시지 형태로 생성하여 전달하고 메시지

수신을 통해 데이터 수신이 가능 인터넷 메일 서비스와 개념이 유사

Linux System Programming 5

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

IPC(Inter-Process Communication) (3)

IPC 와 관련한 시스템 호출 함수 : IPC 시스템 호출 함수 :

Linux System Programming 6

get ctl op

세마포어 semget semctl semop

공유 메모리 shmget shmctlshmop(shmat,

shmdt)

메시지큐 msgget msgctlmsgop(msgsnd

, msgrcv)

기 능 IPC 도구의 생성 및 참조 기능 제공

소유자 및 접근 허가 변경 등의 기능 제공

IPC 도구의 연산( 송수신 제어 등 ) 기능 제공

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

IPC(Inter-Process Communication) (4)

IPC 와 관련한 시스템 호출 함수 : get 시스템 호출

파일 열기 시스템 호출 open 과 유사 새롭게 통신 도구를 생성하거나 이미 생성된 통신 도구에 대한 id 를

반환하여 접근 가능하게 함 반환된 id 는 파일 디스크립터와 비슷하게 동작 접근 허가 또한 파일 접근 허가와 비슷하게 규정

ctl 시스템 호출 통신 도구에 관한 상태 정보 읽기 몇몇 상태 정보 ( 소유자 , 그룹 , 접근 허가 등 ) 에 대한 변경 통신 도구의 제거 기능

op 시스템 호출 프로세스간의 데이터 전송을 실행 파일 시스템 호출 read/write 와 유사 Shmat 는 파일의 open 과 유사하고 , shmdt 는 파일의 close 와

유사Linux System Programming 7

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

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 8

char device Inode # of file

key_t

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

IPC(Inter-Process Communication) (6)

IPC 도구 식별자 : IPC key 변환 시스템 호출 – ftok(file_to_key)

Linux System Programming 9

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

IPC(Inter-Process Communication) (7)

IPC 도구의 상태 자료 구조 : 생성된 IPC 객체에 대한 상태 정보를 저장하는 구조체 IPC 도구 유형별로 별도의 상태 구조체를 지원하나 다음의

접근 허가 구조를 공통으로 포함한다 IPC 도구의 접근 허가 구조 : struct ipc_perm

파일의 접근 허가와 유사한 기능을 지원 접근 모드에서 실행 모드는 무의미함

Linux System Programming 10

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

IPC(Inter-Process Communication) (8)

IPC 도구 테이블 IPC 도구 유형별로 생성된 IPC 객체를 관리하기 위해

운영체제가 유지하는 테이블 IPC 도구 유형별로 각각의 테이블을 유지 파일 테이블과 유사한 개념

Linux System Programming 11

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

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

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

Message QueueMessage Queue

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

메시지 큐 (Message Queue) (1)

메시지 큐 (Message Queue) 프로세스간에 이산적인 데이터를 메시지 형태로 전송하는

통신 도구 파이프와 같이 FIFO 타입의 데이터 전송을 지원 메시지는 메시지와 바이트 (byte) 들의 모임으로 구성

메시지 유형은 정수값으로 여러가지 메시지 형태에 id 를 부여하여 구별하기 위해 사용

바이트 모임은 전송하는 데이터를 의미하는 것으로 문자 , 그림 또는 일련의 구조체 데이터 등을 전송하기 위햇 사용

관련 시스템 호출 함수 msgget() – 메시지 큐를 생성 msgsnd()/msgrcv() – 메시지 전송 및 수신 msgctl() – 메시지 큐 제어

Linux System Programming 14

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

메시지 큐 (Message Queue) (2)

메시지 큐의 구조 : 메시지 큐의 상태

구조체 : msgid_ds 메시지 큐 객체의

상태 정보를 저장하는 구조체

하나의 메시지 큐가 생성되면 하나의 msgid_ds 구조체가 생성

Linux System Programming 15

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

메시지 큐 (Message Queue) (3)

메시지 큐의 동작 : 전송 프로세스가 전송할 데이터를 메시지 형태로 만들어

메시지를 전송하면 전송된 메시지는 메시지 큐의 마지막에 연결된다

수신 프로세스는 메시지 큐에 존재하는 메시지를 선택적으로 수신할 수 있다 .

수신 프로세스에서는 메시지를 수신할 때에 다음의 수신 정책 중에 하나를 지정하여야 한다 .

메시지 큐에서 첫번째 메시지 메시지 큐에서 지정된 타입의 첫번째 메시지 메시지 큐에 있는 타입들의 범위들로 부터 첫번째 메시지

Linux System Programming 16

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

메시지 큐 (Message Queue) (4)

메시지 큐의 생성 : msgget() 메시지 큐 생성 시스템 호출 주어진 key 를 갖는 메시지 큐가 존재하면 메시지 큐의 id

를 반환하고 , 그렇지 않으면 새롭게 메시지 큐를 생성하고 id 를 반환

Linux System Programming 17

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

메시지 큐 (Message Queue) (5)

Linux System Programming 18

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

메시지 큐 (Message Queue) (6)

메시지 큐의 생성 : msgget() msgget() 시스템 호출의 flag 옵션

Linux System Programming 19

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

메시지 큐 (Message Queue) (7)

메시지 큐 구조체 : msqid_ds

Linux System Programming 20

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

메시지 큐 (Message Queue) (8)

메시지 큐 구조체 초기값

Linux System Programming 21

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

메시지 큐 (Message Queue) (9)

메시지 큐의 제어 : msgctl() 메시지 큐 제어 시스템 호출 메시지 큐의 상태를 질의하거나 상태 정보를 변경 , 또는

메시지 큐를 제거하는 기능을 지원

Linux System Programming 22

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

메시지 큐 (Message Queue) (10)

메시지 큐의 제어 : msgctl() msgctl() 시스템 호출의 명령어

Linux System Programming 23

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

메시지 큐 (Message Queue) (11)

msgctl() 시스템 호출의 사용 예 메시지 큐 관련 자료 구조 선언

메시지 큐의 제거

메시지 큐의 소유자 변경

Linux System Programming 24

#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);

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

메시지 큐 (Message Queue) (12)

msgctl() 시스템 호출의 사용 예 메시지 큐의 접근 허가 변경

메시지 큐의 메시지 크기 변경

Linux System Programming 25

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);

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

메시지 큐 (Message Queue) (13)

메시지 큐의 연산 : msgsnd(), msgrcv() 메시지 구조체 :

메시지 유형은 전송되는 여러가지 유형의 메시지 형태를 분류하여 지정

메시지 텍스트는 전송하는 데이터를 저장 메시지 텍스트의 크기는 최소 0 에서 최대 64 KB 이내이며 ,

묵시적으로 2048 바이트로 사용

Linux System Programming 26

#include <sys/msg.h>struct msgbuf { long mtype; /* 메시지 유형 */ char mtext[1]; /* 메지시 텍스트 */}

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

메시지 큐 (Message Queue) (14)

메시지 송신 시스템 호출 : msgsnd()

Linux System Programming 27

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

메시지 큐 (Message Queue) (15)

메시지 송신 시스템 호출 : msgsnd() msgsnd 시스템 호출에 의한 메시지 큐 구조체 변경

Linux System Programming 28

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

메시지 큐 (Message Queue) (16)

메시지 수신 시스템 호출 : msgrcv()

Linux System Programming 29

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

메시지 큐 (Message Queue) (17)

메시지 수신 시스템 호출 : msgrcv() msgrcv() 시스템 호출에서의 메시지 타입 지정

Linux System Programming 30

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

예제 프로그램 #1 (1)

하나의 메시지를 전송하고 수신하는 프로그램

Linux System Programming 31

// 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);}

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

예제 프로그램 #1 (2)

Linux System Programming 32

// 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); }

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

예제 프로그램 #2 (1)

예제 프로그램 #1 을 개선하여 여러 개의 메시지를 송수신하는 프로그램

Linux System Programming 33

// 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;

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

예제 프로그램 #2 (2)

Linux System Programming 34

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); }

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

예제 프로그램 #2 (3)

Linux System Programming 35

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);}

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

예제 프로그램 #2 (4)

Linux System Programming 36

// 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;

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

예제 프로그램 #2 (5)

37

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);}

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

예제 프로그램 #3 (1) 메시지 송신 프로그램가 키보드 입력을 메시지로 만들어 여러

개의 수신 프로그램에 전달하는 프로그램 송신 프로그램은 fork()/exec() 시스템 호출을 통하여 수신

프로세스를 생성하고 , 수신 프로세스는 수신된 메시지를 표준 출력으로 출력하도록 한다 .

Linux System Programming 38

// 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

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

예제 프로그램 #3 (2)

Linux System Programming 39

#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;

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

예제 프로그램 #3 (3)

Linux System Programming 40

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);

}

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

예제 프로그램 #3 (4)

Linux System Programming 41

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);}

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

예제 프로그램 #3 (5)

Linux System Programming 42

WAIT_SOLE_USE(msgqid);msgctl(msgqid,IPC_RMID,0);exit(0);

}

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

예제 프로그램 #3 (6)

Linux System Programming 43

// 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;

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

예제 프로그램 #3 (7)

Linux System Programming 44

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);

}

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

SemaphoreSemaphore

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

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

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

세마포어 (Semaphore) (2)

세마포어 (Semaphore) ( 계속 ) 세마포어 연산 P & V 는 원자적 연산 (atomic operation)

하나의 프로세스가 P 또는 V 연산을 실행하는 도중에는 중지하지 않는다

어떤 프로세스가 P 또는 V 연산을 이용하여 세마포어에 접근하는 동안에는 다른 프로세스가 세마포어 값을 변경할 수 없다

세마포어의 활용 상호 배제 (mutual exclusion) 문제 – 두 개 이상의

프로세스가 하나의 공유 자원을 접근할 때에 한 순간에 하나의 프로세스만 공유 자원을 접근할 수 있도록 보장함

실행 동기화 – 두 개 이상의 프로세스간에 실행 순서에 맞추어 실행됨을 보장함

Linux System Programming 47

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

세마포어 (Semaphore) (3)

세마포어 종류 : 이진 세마포어 (Binary Semaphore)

0 또는 1 의 정수 값만 가지는 세마포어 P(s) 연산은 세마포어 s 가 1 일 때에 0 으로 변경 V(s) 연산은 세마포어 s 가 0 일 때에 1 로 변경 하나의 자원에 대한 공유 및 동기화를 지원

계수형 세마포어 (Counting Semaphore) 범위에 제한이 없는 정수 값을 가지는 세마포어 일반적으로 언급하는 세마포어 다수의 공유 자원에 대해 여러 프로세스가 접근할 때에 상호

배제 및 동기화를 지원

Linux System Programming 48

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

세마포어 (Semaphore) (4) 세마포어 이용 - 공유 자원에 대한 상호 배제 (Mutual

Exclusion) 여러 개의 프로세스가 하나의 자원을 공유하는 경우 , 동시에 여러

프로세스가 자원을 접근하면 예상하지 못하는 문제가 발생함 예 : 동시에 여러 프로그램이 프린터에 출력을 시도하는 경우

해결책 – 상호 배제 한 순간에 하나의 프로세스만 공유 자원을 접근함을 보장함 임계 영역 (Critical Section) : 전체 프로그램 중에서 공유자원을

접근하는 프로그램 영역 한 순간에 임계 영역을 실행하는 프로세스는 하나만 존재하도록 보장함

세마포어를 이용하여 상호 배제를 구현 공유자원의 갯수에 따라 이진 세마포어 또는 계수형 세마포어를 사용 공유 자원에 대한 잠금과 풀기 (lock & unlock) 기능을 지원

Linux System Programming 49

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

세마포어 (Semaphore) (5) 세마포어 이용 - 공유 자원에 대한 상호 배제 (Mutual

Exclusion)

Linux System Programming 50

Critical Section

Critical Section공유 자원

프로세스 P1 프로세스 P2세마포어 s( 초기값 : 1)

P(s)

V(s)

P(s)

V(s)

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

세마포어 (Semaphore) (6) 세마포어 이용 - 프로세스간의 실행 동기화 (Synchronization)

하나의 프로그램이 여러 개의 프로세스로 이루어지는 경우 , 프로세스간의 종속성에 의해 실행 순서가 정해지며 , 반드시 실행 순서에 의해 동작하여함

예 : 하나의 프로세스가 다른 프로세스가 제공하는 데이터를 받아 동작하는 경우

해결책 – 프로세스 실행 동기화 프로세서 P1 가 T1 문장을 실행한 후에 프로세스 P2 가 T2 문장을

실행하여야 하는 경우 프로세스 P2 는 T2 문자을 실행하기 전에 프로세스 P1 이 T1 문장을

실행하여는지를 검사 프로세스 P1 이 T1 문장을 실행하였으면 바로 T2 문장을 실행 프로세스 P1 이 T2 문장을 실행하지 않았으면 실행할 때까지 대기

세마포어를 이용하여 동기화를 지원함 대개의 경우 이진 세마포어를 사용

Linux System Programming 51

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

세마포어 (Semaphore) (7) 세마포어 이용 - 프로세스간의 실행 동기화 (Synchronization)

Linux System Programming 52

프로세스 P2

T2: -----

프로세스 P1

T1: -----

세마포어 s( 초기값 : 0)

V(s) P(s)

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

세마포어 (Semaphore) (8)

세마포어의 생성 : semget()

Linux System Programming 53

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

세마포어 (Semaphore) (9)

세마포어의 생성 : semget()

Linux System Programming 54

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

세마포어 (Semaphore) (10)

세마포어의 생성 : semget() semget() 시스템 호출의 동작

Linux System Programming 55

세마포어 구조체 초기화 :

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

세마포어 (Semaphore) (11)

세마포어의 제어 : semctl() 세마포어 제어 연산

1. 세마포어의 집합 안에 개별적인 세마포어나 모든 세마포어에 대해 세마포어 값을 읽어오거나 새로운 값을 설정

2. 세마포어 집합의 상태 정보을 읽어오거나 변경3. 세마포어에서 대기중인 프로세스의 수를 결정4. 마지막으로 세마포어를 연산한 프로세스를 결정5. 세마포어를 제거

semctl () 시스템 호출을 통해 상기의 세마포어 제어 연산을 실행

Linux System Programming 56

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

세마포어 (Semaphore) (12)

세마포어의 제어 : semctl()

Linux System Programming 57

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

세마포어 (Semaphore) (13)

세마포어의 제어 : semctl() semctl() 시스템 호출의 명령어 및 반환값

Linux System Programming 58

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

세마포어 (Semaphore) (14)

세마포어의 제어 : semctl() 세마포어 생성

세마포어 집합에서 하나의 세마포어를 초기화

세마포어 집합에서 하나의 세마포어 값 읽기

Linux System Programming 59

#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);

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

세마포어 (Semaphore) (15)

세마포어의 제어 : semctl() 세마포어 집합 내의 모든 세마포어의 값을 초기화

세마포어 집합 내의 모든 세마포어의 값 읽기

세마포어의 소유자 변경

세마포어 집합 제거

Linux System Programming 60

semctl(semid, ANY, SETALL, init_us);

// 접근 허가 모드 변경에도 같은 형태로 사용

semctl(semid, ANY, IPC_STAT, &semds);

semds.sem_perm.uid = 51;

semctl(semid, ANY, IPC_SET, &ds);

semctl(semid, ANY, IPC_RMID, ANY);

semctl(semid, ANY, GETALL, us);

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

세마포어 (Semaphore) (16)

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

Linux System Programming 61

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

세마포어 (Semaphore) (17)

Linux System Programming 62

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

세마포어 (Semaphore) (18)

Linux System Programming 63

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

예제 프로그램 #4 (1)

세마포어를 이용하여 공유 자원에 대한 접근을 제어하는 프로그램 공유 자원은 표준 출력

64

// 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);

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

예제 프로그램 #4 (2)

Linux System Programming 65

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);

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

예제 프로그램 #4 (3)

Linux System Programming 66

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); } }}

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

예제 프로그램 #5 (1) 다음 그림과 세 개의

세마포어를 갖는 세마포어 집합을 이용하여 프린터 자원을 관리하는 프로그램

첫번째 세마포어는 두 개의 프린터 모두를 관리하는 계수형 세마포어

두번째 및 세번째 세마포어는 각각 프린터 1 과 프린터 2 를 관리하는 세마포어

프린터는 단말기 장치를 PRINTER1 으로 , 정규 파일을 PRINTER2 로 환경 변수를 정의하여 시뮬레이션한다

67

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

예제 프로그램 #5 (2)

68

#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);

}

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

예제 프로그램 #5 (3)

69

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;

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

예제 프로그램 #5 (4)

70

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);

}

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

예제 프로그램 #6 (1) 다음 그림과 같은 생산

라인을 시뮬레이션하는 프로그램

각 공정은 다중 프로세스를 생성하고 이들의 생산 순서와 소비 시간을 세마포어와 프로세스 수면 (sleep) 을 이용하여 시뮬레이션한다

71

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

예제 프로그램 #6 (2)

72

//// header file name : ex10-3.h//

#define NWIDGETS 5#define PARTA 0#define PARTB 1#define PARTC 2#define SUB1 3#define HOLDER 0

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

예제 프로그램 #6 (3)

73

//// 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); }

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

예제 프로그램 #6 (4)

74

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);}

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

예제 프로그램 #6 (5)

75

//// 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]); }}

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

예제 프로그램 #6 (6)

76

//// 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); }}

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

Shared MemoryShared Memory

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

공유메모리 (Shared Memory) (1)

공유메모리 (Shared memory) 두 개이상의 프로세스가 실제 메모리의 일부를 공유하여 통신할

수 있는 IPC 도구 통신하려는 프로세스는 우선 공유 메모리를 할당받는다 프로세스는 할당된 공유 메모리를 자신의 가상주소공간 일부에 붙여 (attach) 메모리에 데이터를 읽고 쓰는 것가 동일한 방법으로 필요한 데이터를 읽거나 전송하려는 데이터를 기록하여 상호 통신한다

프로세스간의 통신이 종료되면 공유 메모리를 가상주소공간에서 떼어내고 (detach) 공유 메모리를 해제한다

IPC 도구 중에서 가장 효율적 시스템 간의 이식성이 낮음

프로세스간의 메모리 공유를 위해 별도의 하드웨어 지원이 필요 공유 메모리를 사용한 프로그램을 하드웨어 지원이 없는

시스템에서는 사용불가Linux System Programming 78

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

공유메모리 (Shared Memory) (2)

공유 메모리 시스템 호출 : shmget – 공유 메모리를 새롭게 할당하거나 할당된 공유

메모리의 핸들을 반환한다 shmctl – 공유 메모리와 관련된 상태 변수값을 변경하거나

공유 메모리를 제거한다 shmat – 공유 메모리를 프로세스의 가상주소공간에 논리적으로 부착 (attach) 한다

shmdt – 프로세스의 가상주소공간으로부터 공유 메모리를 분리한다

Linux System Programming 79

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

공유메모리 (Shared Memory) (3)

공유 메모리 시스템 호출 :

Linux System Programming 80

프로세스 P2프로세스 P1

가상주소 :

10000

shmat()

shmdt()가상주소 :20000

shmat()

shmdt()

공유메모리

shmget()

shmctl()

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

공유메모리 (Shared Memory) (4)

공유 메모리의 생성 : shmget()

Linux System Programming 81

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

공유메모리 (Shared Memory) (5)

공유 메모리의 생성 : shmget() 공유 메모리 구조체

Linux System Programming 82

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

공유메모리 (Shared Memory) (6)

공유 메모리의 생성 : shmget() 공유 메모리 구조체의 초기화

Linux System Programming 83

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

공유메모리 (Shared Memory) (7)

공유 메모리의 제어 : shmctl()

Linux System Programming 84

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

공유메모리 (Shared Memory) (8)

공유 메모리의 제어 : shmctl() shmctl() 시스템 호출의 명령어

Linux System Programming 85

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

공유메모리 (Shared Memory) (9)

공유 메모리의 연산 : shmat() / shmdt()

Linux System Programming 86

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

예제 프로그램 #7 (1) 학원 강좌 예약 시스템 프로그램 부모 프로세스는 강좌 예약 정보를 갖는 공유 메모리을 할당하

고 , 공유 메모리에 대한 상호배제를 위한 세마포어를 생성한다 자식 프로세스을 생성하여 강좌 예약을 수행하는데 , 자식

프로세스는 주기적으로 강좌 예약을 수행하도록 시뮬레이션하며 , 더 이상 예약할 좌석 (seat) 가 없으면 종료한다

부모 프로세스는 모든 자식 프로세스가 종료할 때까지 기다렸다가 세마포어와 공유 메모리를 제거하고 종료한다

87

// // 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;

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

예제 프로그램 #7 (2)

Linux System Programming 88

// 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 3int 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;

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

예제 프로그램 #7 (3)

89

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);

}

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

예제 프로그램 #7 (4)

90

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);

}

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

예제 프로그램 #7 (5)

91

void rpterror(char *string){

char errline[50];sprintf(errline,"%s %s",string, pname);perror(errline);

}

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

예제 프로그램 #7 (6)

92

// 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);

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

예제 프로그램 #7 (7)

93

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);}

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

예제 프로그램 #7 (8)

94

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);

}

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

예제 프로그램 #8 (1) 세마포어와 공유 메모리를 이용하여 버퍼의 자료를 생산하고

소비하는 생산자 /소비자 (producer/consumer) 프로그램 생산자는 공유 메모리를 할당하여 버퍼를 설정한다 생산자와 소비자 사이에 버퍼 접근을 위한 동기화를 위해 2

개의 세마포어를 생성하여 사용한다 버퍼 쓰기 동기화 (consumed 동기화 ) - 생산자는 소비자가 버퍼의 자료를 읽고 간 후에 새로운 자료를 버퍼에 쓴다

버퍼 읽기 동기화 (produced 동기화 ) - 소비자는 생산자가 버퍼에 새로운 자료를 쓴 후에 자료를 읽어간다

95

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

예제 프로그램 #8 (2)

96

// 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();

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

예제 프로그램 #8 (3)

97

/* 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); }

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

예제 프로그램 #8 (4)

98

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);}

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

예제 프로그램 #8 (5)

99

// 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.*/

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

예제 프로그램 #8 (6)

100

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); }

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

예제 프로그램 #8 (7)

101

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);}