Linux System Programming

32
Linux System Linux System Programming Programming Lecture #10 – 세세세세 (Semaphore)

description

Linux System Programming. Lecture #10 – 세마포어 (Semaphore). 세마포어 (Semaphore) (1). 세마포어 정의 : 실행단위 ( 프로세스 또는 쓰레드 ) 간의 동기화 도구 2 개의 원자적 연산 P 와 V 가 정의되어 있는 , 정수값을 가지는 객체 s : 세마포어 P(s) : if ( s > 0 ) then s-- else 현재 프로세스는 대기한다 ; V(s) : - PowerPoint PPT Presentation

Transcript of Linux System Programming

Page 1: Linux System Programming

Linux System Linux System ProgrammingProgramming

Lecture #10 – 세마포어 (Semaphore)

Page 2: Linux System Programming

Linux System Programming 2

세마포어 (Semaphore) (1)세마포어 (Semaphore) (1)

세마포어 정의 : 실행단위 (프로세스 또는 쓰레드 ) 간의 동기화 도구 2 개의 원자적 연산 P 와 V 가 정의되어 있는 ,정수값을 가지는

객체 s : 세마포어 P(s) :

if ( s > 0 ) then s--else

현재 프로세스는 대기한다 ; V(s) :

if ( 1 개 이상의 프로세스가 대기중 ) then 1 개 프로세스만 진행한다

else s++;

일상 생활에서의 ‘신호등’과 같은 동작을 수행 철도 교통을 통제하기 위한 깃발신호로부터 유래

Page 3: Linux System Programming

Linux System Programming 3

세마포어 (Semaphore) (2)세마포어 (Semaphore) (2)

세마포어 정의 : 세마포어 연산 P & V 는 원자적 연산 (atomic operation)

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

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

세마포어의 활용 상호 배제 (mutual exclusion) 문제 – 두 개 이상의 프로세스가 하나의 공유 자원을 접근할 때에 한 순간에 하나의 프로세스만 공유 자원을 접근할 수 있도록 보장함

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

Page 4: Linux System Programming

Linux System Programming 4

세마포어 (Semaphore) (3)세마포어 (Semaphore) (3)

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

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

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

동기화를 지원

Page 5: Linux System Programming

Linux System Programming 5

세마포어 (Semaphore) (4)세마포어 (Semaphore) (4)

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

여러 개의 프로세스가 하나의 자원을 공유하는 경우 , 동시에 여러 프로세스가 자원을 접근하면 예상하지 못하는 문제가 발생함

예 : 동시에 여러 프로그램이 프린터에 출력을 시도하는 경우

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

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

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

Page 6: Linux System Programming

Linux System Programming 6

세마포어 (Semaphore) (5)세마포어 (Semaphore) (5)

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

Critical Section

Critical Section

공유 자원

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

P(s)

V(s)

P(s)

V(s)

Page 7: Linux System Programming

Linux System Programming 7

세마포어 (Semaphore) (6)세마포어 (Semaphore) (6)

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

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

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

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

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

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

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

Page 8: Linux System Programming

Linux System Programming 8

프로세스 P2

T2: -----

프로세스 P1

T1: -----

세마포어 (Semaphore) (7)세마포어 (Semaphore) (7)

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

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

V(s) P(s)

Page 9: Linux System Programming

Linux System Programming 9

세마포어 (Semaphore) (8)세마포어 (Semaphore) (8)

세마포어의 생성 : semget 시스템 호출

Page 10: Linux System Programming

Linux System Programming 10

세마포어 (Semaphore) (9)세마포어 (Semaphore) (9)

세마포어의 생성 : semget 시스템 호출 세마포어 구조체 :

Page 11: Linux System Programming

Linux System Programming 11

세마포어 (Semaphore) (10)세마포어 (Semaphore) (10)

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

세마포어 구조체 초기화 :

Page 12: Linux System Programming

Linux System Programming 12

세마포어 (Semaphore) (11)세마포어 (Semaphore) (11)

세마포어의 제어 : semctl 시스템 호출 세마포어 제어 연산

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

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

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

Page 13: Linux System Programming

Linux System Programming 13

세마포어 (Semaphore) (12)세마포어 (Semaphore) (12)

세마포어의 제어 : semctl 시스템 호출

Page 14: Linux System Programming

Linux System Programming 14

세마포어 (Semaphore) (13)세마포어 (Semaphore) (13)

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

Page 15: Linux System Programming

Linux System Programming 15

세마포어 (Semaphore) (14)세마포어 (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);

Page 16: Linux System Programming

Linux System Programming 16

세마포어 (Semaphore) (15)세마포어 (Semaphore) (15)

세마포어의 제어 : semctl 시스템 호출 세마포어 집합 내의 모든 세마포어의 값을 초기화

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

세마포어의 소유자 변경

세마포어 집합 제거

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 17: Linux System Programming

Linux System Programming 17

세마포어 (Semaphore) (16)세마포어 (Semaphore) (16)

세마포어의 제어 : semop 시스템 호출 세마포어의 값을 증가시키거나 감소시키는 연산을 수행

Page 18: Linux System Programming

Linux System Programming 18

세마포어 (Semaphore) (17)세마포어 (Semaphore) (17)

세마포어의 제어 : semop 시스템 호출

Page 19: Linux System Programming

Linux System Programming 19

세마포어 (Semaphore) (18)세마포어 (Semaphore) (18)

세마포어의 제어 : semop 시스템 호출

Page 20: Linux System Programming

Linux System Programming 20

예제 프로그램 (1)예제 프로그램 (1)

예제 10-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);

Page 21: Linux System Programming

Linux System Programming 21

예제 프로그램 (2)예제 프로그램 (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); if(semop(semid,&unlock,1) == -1) { perror(argv[0]); exit(4); } }

Page 22: Linux System Programming

Linux System Programming 22

예제 프로그램 (3)예제 프로그램 (3)

if(creator) { sleep(5); if(semctl(semid,DUMMY,IPC_RMID,DUMMY) == -1) { perror(argv[0]); exit(5); } }}

Page 23: Linux System Programming

Linux System Programming 23

예제 프로그램 (4)예제 프로그램 (4)

예제 10-2 다음 그림과 세 개의

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

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

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

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

Page 24: Linux System Programming

Linux System Programming 24

예제 프로그램 (5)예제 프로그램 (5)

#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 25: Linux System Programming

Linux System Programming 25

예제 프로그램 (6)예제 프로그램 (6)

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 26: Linux System Programming

Linux System Programming 26

예제 프로그램 (7)예제 프로그램 (7)

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

}}

Page 27: Linux System Programming

Linux System Programming 27

예제 프로그램 (8)예제 프로그램 (8)

예제 10-3 다음 그림과 같은 생산

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

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

Page 28: Linux System Programming

Linux System Programming 28

예제 프로그램 (9)예제 프로그램 (9)

//// 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 29: Linux System Programming

Linux System Programming 29

예제 프로그램 (10)예제 프로그램 (10)

//// 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 30: Linux System Programming

Linux System Programming 30

예제 프로그램 (11)예제 프로그램 (11)

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

Page 31: Linux System Programming

Linux System Programming 31

예제 프로그램 (12)예제 프로그램 (12)

//// 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 32: Linux System Programming

Linux System Programming 32

예제 프로그램 (13)예제 프로그램 (13)

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