Download presentation
Presentation is loading. Please wait.
1
Linux System Programming
Lecture #10 – 세마포어(Semaphore)
2
세마포어(Semaphore) (1) 세마포어 정의 : 실행단위(프로세스 또는 쓰레드) 간의 동기화 도구
2개의 원자적 연산 P와 V가 정의되어 있는,정수값을 가지는 객체 s : 세마포어 P(s) : if ( s > 0 ) then s-- else 현재 프로세스는 대기한다; V(s) : if ( 1개 이상의 프로세스가 대기중 ) then 개 프로세스만 진행한다 else s++; 일상 생활에서의 ‘신호등’과 같은 동작을 수행 철도 교통을 통제하기 위한 깃발신호로부터 유래 Linux System Programming
3
세마포어(Semaphore) (2) 세마포어 정의 : 세마포어 연산 P & V 는 원자적 연산(atomic operation)
세마포어의 활용 상호 배제(mutual exclusion) 문제 – 두 개 이상의 프로세스가 하나의 공유 자원을 접근할 때에 한 순간에 하나의 프로세스만 공유 자원을 접근할 수 있도록 보장함 실행 동기화 – 두 개 이상의 프로세스간에 실행 순서에 맞추어 실행됨을 보장함 Linux System Programming
4
세마포어(Semaphore) (3) 세마포어 종류 : 이진 세마포어(Binary Semaphore)
0 또는 1의 정수 값만 가지는 세마포어 P(s) 연산은 세마포어 s가 1일 때에 0으로 변경 V(s) 연산은 세마포어 s가 0일 때에 1로 변경 하나의 자원에 대한 공유 및 동기화를 지원 계수형 세마포어(Counting Semaphore) 범위에 제한이 없는 정수 값을 가지는 세마포어 일반적으로 언급하는 세마포어 다수의 공유 자원에 대해 여러 프로세스가 접근할 때에 상호 배제 및 동기화를 지원 Linux System Programming
5
세마포어(Semaphore) (4) 세마포어 이용 : 공유 자원에 대한 상호 배제(Mutual Exclusion)
여러 개의 프로세스가 하나의 자원을 공유하는 경우, 동시에 여러 프로세스가 자원을 접근하면 예상하지 못하는 문제가 발생함 예: 동시에 여러 프로그램이 프린터에 출력을 시도하는 경우 해결책 – 상호 배제 한 순간에 하나의 프로세스만 공유 자원을 접근함을 보장함 임계 영역(Critical Section) : 전체 프로그램 중에서 공유자원을 접근하는 프로그램 영역 한 순간에 임계 영역을 실행하는 프로세스는 하나만 존재하도록 보장함 세마포어를 이용하여 상호 배제를 구현함 공유자원의 갯수에 따라 이진 세마포어 또는 계수형 세마포어를 사용 공유 자원에 대한 잠금과 풀기(lock & unlock) 기능을 지원 Linux System Programming
6
세마포어(Semaphore) (5) 세마포어 이용 : 공유 자원에 대한 상호 배제(Mutual Exclusion)
(초기값: 1) P(s) P(s) Critical Section 공유 자원 Critical Section V(s) V(s) Linux System Programming
7
세마포어(Semaphore) (6) 세마포어 이용 : 프로세스간의 실행 동기화(Synchronization)
하나의 프로그램이 여러 개의 프로세스로 이루어지는 경우, 프로세스간의 종속성에 의해 실행 순서가 정해지며, 반드시 실행 순서에 의해 동작하여함 예: 하나의 프로세스가 다른 프로세스가 제공하는 데이터를 받아 동작하는 경우 해결책 – 프로세스 실행 동기화 프로세서 P1가 T1 문장을 실행한 후에 프로세스 P2가 T2 문장을 실행하여야 하는 경우 프로세스 P2는 T2 문자을 실행하기 전에 프로세스 P1이 T1 문장을 실행하여는지를 검사 프로세스 P1이 T1 문장을 실행하였으면 바로 T2 문장을 실행 프로세스 P1이 T2 문장을 실행하지 않았으면 실행할 때까지 대기 세마포어를 이용하여 동기화를 지원함 대개의 경우 이진 세마포어를 사용 Linux System Programming
8
세마포어(Semaphore) (7) 세마포어 이용 : 프로세스간의 실행 동기화(Synchronization) 프로세스 P1
(초기값: 0) V(s) P(s) Linux System Programming
9
세마포어(Semaphore) (8) 세마포어의 생성: semget 시스템 호출 Linux System Programming
10
세마포어(Semaphore) (9) 세마포어의 생성: semget 시스템 호출 세마포어 구조체:
Linux System Programming
11
세마포어(Semaphore) (10) 세마포어의 생성: semget 시스템 호출 Semget 시스템 호출의 동작
세마포어 구조체 초기화: Linux System Programming
12
세마포어(Semaphore) (11) 세마포어의 제어: semctl 시스템 호출 세마포어 제어 연산
세마포어의 집합 안에 개별적인 세마포어나 모든 세마포어에 대해 세마포어 값을 읽어오거나 새로운 값을 설정 세마포어 집합의 상태 정보을 읽어오거나 변경 세마포어에서 대기중인 프로세스의 수를 결정 마지막으로 세마포어를 연산한 프로세스를 결정 세마포어를 제거 semctl 시스템 호출을 통해 상기의 세마포어 제어 연산을 실행 Linux System Programming
13
세마포어(Semaphore) (12) 세마포어의 제어: semctl 시스템 호출 Linux System Programming
14
세마포어(Semaphore) (13) 세마포어의 제어: semctl 시스템 호출 semctl 시스템 호출의 명령어 및 반환값
Linux System Programming
15
세마포어(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
16
세마포어(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
17
세마포어(Semaphore) (16) 세마포어의 제어: semop 시스템 호출
세마포어의 값을 증가시키거나 감소시키는 연산을 수행 Linux System Programming
18
세마포어(Semaphore) (17) 세마포어의 제어: semop 시스템 호출 Linux System Programming
19
세마포어(Semaphore) (18) 세마포어의 제어: semop 시스템 호출 Linux System Programming
20
예제 프로그램 (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); Linux System Programming
21
예제 프로그램 (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); Linux System Programming
22
예제 프로그램 (3) if(creator) { sleep(5);
if(semctl(semid,DUMMY,IPC_RMID,DUMMY) == -1) { perror(argv[0]); exit(5); } Linux System Programming
23
예제 프로그램 (4) 예제 10-2 다음 그림과 세 개의 세마포어를 갖는 세마포어 집합을 이용하여 프린터 자원을 관리하는 프로그램 첫번째 세마포어는 두 개의 프린터 모두를 관리하는 계수형 세마포어 두번째 및 세번째 세마포어는 각각 프린터1과 프린터2를 관리하는 세마포어 프린터는 단말기 장치를 PRINTER1으로, 정규 파일을 PRINTER2로 환경 변수를 정의하여 시뮬레이션한다 Linux System Programming
24
예제 프로그램 (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); } Linux System Programming
25
예제 프로그램 (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; Linux System Programming
26
예제 프로그램 (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; sprintf(errmsg,"%s - RELEASE", argv[0]); perror(errmsg); exit(7); Linux System Programming
27
예제 프로그램 (8) 예제 10-3 다음 그림과 같은 생산 라인을 시뮬레이션하는 프로그램
각 공정은 다중 프로세스를 생성하고 이들의 생산 순서와 소비 시간을 세마포어와 프로세스 수면(sleep)을 이용하여 시뮬레이션한다 Linux System Programming
28
예제 프로그램 (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 Linux System Programming
29
예제 프로그램 (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); } Linux System Programming
30
예제 프로그램 (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(); Linux System Programming
31
예제 프로그램 (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]); } Linux System Programming
32
예제 프로그램 (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); } Linux System Programming
Similar presentations