13 장 프로세스 사이의 통신

33
13 장 장장장장 장장장 장장 장장장 1

Upload: italia

Post on 17-Jan-2016

53 views

Category:

Documents


1 download

DESCRIPTION

13 장 프로세스 사이의 통신. 창병모. 13.1 파일 및 레코드 잠금. 파일 및 레코드 잠금의 원리. 어떻게 프로세스 사이에 데이터를 주고받을 수 있을까 ? 한 프로세스가 파일에 쓴 내용을 다른 프로세스가 읽음 문제점 한 프로세스가 파일 내용을 수정하는 동안에 다른 프로세스가 그 파일을 읽는 경우 두 개의 프로세스가 하나의 파일에 동시에 접근하여 데이터를 쓰는 경우. 잠금 (lock). 파일 혹은 레코드 ( 파일의 일부 영역 ) 잠금 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 13 장 프로세스 사이의 통신

13 장 프로세스 사이의 통신

창병모

1

Page 2: 13 장 프로세스 사이의 통신

13.1 파일 및 레코드 잠금

2

Page 3: 13 장 프로세스 사이의 통신

파일 및 레코드 잠금의 원리 어떻게 프로세스 사이에 데이터를 주고받을 수 있을까 ?

한 프로세스가 파일에 쓴 내용을 다른 프로세스가 읽음

문제점 한 프로세스가 파일 내용을 수정하는 동안에 다른 프로세스가

그 파일을 읽는 경우 두 개의 프로세스가 하나의 파일에 동시에 접근하여 데이터를

쓰는 경우

3

Page 4: 13 장 프로세스 사이의 통신

잠금 (lock) 파일 혹은 레코드 ( 파일의 일부 영역 ) 잠금

한 프로세스가 그 영역을 읽거나 수정할 때 다른 프로세스의 접근을 제한

잠금된 영역에 한 번에 하나의 프로세스만 접근 특히 레코드에 쓰기를 할 경우 대상 레코드에 대해 잠금을

해서 다른 프로세스가 접근하지 못하게 해야 한다 .

4

Page 5: 13 장 프로세스 사이의 통신

잠금이 필요한 예 잠금 없음

(1) 프로세스 A 가 잔액을 읽는다 :

잔액 100 만원(2) 프로세스 B 가 잔액을 읽는다 :

잔액 100 만원(3) 프로세스 B 가 잔액에 입금액을

더하여 레코드를 수정한다 : 잔액 120 만원

(4) 프로세스 A 가 잔액에 입금액을 더하여 레코드를 수정한다 : 잔액 110 만원

잠금 사용

(1) 프로세스 A 가 레코드에 잠금을 하고 잔액을 읽는다 : 잔액 100 만원

(2) 프로세스 A 가 잔액에 입금액을 더하여 레코드를 수정하고 잠금을 푼다 : 잔액 110 만원

(3) 프로세스 B 가 레코드에 잠금을 하고 잔액을 읽는다 : 잔액 110 만원

(4) 프로세스 B 가 잔액에 입금액을 더하여 레코드를 수정하고 잠금을 푼다 : 잔액 130 만원

5

Page 6: 13 장 프로세스 사이의 통신

잠금 구현 fcntl( ) 함수

파일 및 레코드 잠금을 구현할 수 있다 .

잠금의 종류 F_RDLCK : 여러 프로세스가 공유 가능한 읽기 잠금 F_WRLCK : 한 프로세스만 가질 수 있는 배타적인 쓰기 잠금

6

대상영역의현재잠금

상태읽기잠금요청 쓰기잠금요청

잠금없음 승인 승인

하나이상의읽기잠금 승인 거절

하나의쓰기잠금 거절 거절

Page 7: 13 장 프로세스 사이의 통신

잠금 함수 : fcntl()

fd는 대상이 되는 파일 디스크립터 cmd

F_GETLK : 잠금 검사 F_SETLK : 잠금 설정 혹은 해제 F_SETLKW: 잠금 설정 ( 블로킹 버전 ) 혹은 해제

flock 구조체 잠금 종류 , 프로세스 ID, 잠금 위치 등

7

#include <sys/types.h>#include <unistd.h>#include <fcntl.h>int fcntl(int fd, int cmd, struct flock *lock);cmd 에 따라 잠금 검사 혹은 잠금 설정을 한다 . 성공하면 0 실패하면 -1 을 리턴

Page 8: 13 장 프로세스 사이의 통신

flock 구조체struct flock {

short l_type; // 잠금 종류 : F_RDLCK, F_WRLCK, F_UNLCK

off_t l_start; // 잠금 시작 위치 : 바이트 오프셋 short l_whence; // 기준 위치 : SEEK_SET, SEEK_CUR, SEEK_END

off_t l_len; // 잠금 길이 : 바이트 수 (0 이면 파일끝까지 )

pid_t l_pid; // 프로세스 번호};

8

Page 9: 13 장 프로세스 사이의 통신

잠금 예제 학생 레코드를 질의하는 프로그램 : rdlock.c 학생 레코드를 수정하는 프로그램 : wrlock.c 수정 프로그램에서 어떤 레코드를 수정하는 중에는 질의

프로그램에서 그 레코드를 읽을 수 없도록 레코드 잠금을 이용하여 제한한다 .

프로그램에 대한 자세한 설명 : 교재 412-415 참조

9

Page 10: 13 장 프로세스 사이의 통신

rdlock.c1 #include <stdio.h>

2 #include <fcntl.h>

3 #include "student.h"

4 #define START_ID 1201001

5

6 /* 잠금을 이용한 학생 데이터베이스 질의 프로그램 */

7 int main(int argc, char *argv[])

8 {

9 int fd, id;

10 struct student record;

11 struct flock lock;

12

13 if (argc < 2) {

14 fprintf(stderr, " 사용법 : %s 파일 \n", argv[0]);

15 exit(1);

16 }

10

Page 11: 13 장 프로세스 사이의 통신

rdlock.c18 if ((fd = open(argv[1], O_RDONLY)) == -1) {

19 perror(argv[1]);

20 exit(2);

21 }

22

23 printf("\n 검색할 학생의 학번 입력 :");

24 while (scanf("%d", &id) == 1) {

25 lock.l_type = F_RDLCK;

26 lock.l_whence = SEEK_SET;

27 lock.l_start = (id-START_ID)*sizeof(record);

28 lock.l_len = sizeof(record);

29 if (fcntl(fd,F_SETLKW, &lock) == -1) { /* 읽기 잠금 */

30 perror(argv[1]);

31 exit(3);

32 }

33

11

Page 12: 13 장 프로세스 사이의 통신

rdlock.c34 lseek(fd, (id-START_ID)*sizeof(record), SEEK_SET);

35 if ((read(fd, (char *) &record, sizeof(record)) > 0) && (record.id != 0))

37 printf(" 이름 :%s\t 학번 :%d\t 점수 :%d\n", record.name, record.id,

38 record.score);

39 else printf(" 레코드 %d 없음 \n", id);

40

41 lock.l_type = F_UNLCK;

42 fcntl(fd,F_SETLK, &lock); /* 잠금 해제 */

43 printf("\n 검색할 학생의 학번 입력 :");

44 }

45

46 close(fd);

47 exit(0);

48 }

12

Page 13: 13 장 프로세스 사이의 통신

wrlock.c1 #include <stdio.h>2 #include <fcntl.h>3 #include "student.h"4 #define START_ID 120100156 /* 잠금을 이용한 학생 데이터베이스 수정 프로그램 */7 int main(int argc, char *argv[])8 {9 int fd, id;10 struct student record;11 struct flock lock;1213 if (argc < 2) {14 fprintf(stderr, " 사용법 : %s 파일 \n", argv[0]);15 exit(1);16 }17

13

Page 14: 13 장 프로세스 사이의 통신

wrlock.c18 if ((fd = open(argv[1], O_RDWR)) == -1) {19 perror(argv[1]);20 exit(2);21 }2223 printf("\n 수정할 학생의 학번 입력 :");24 while (scanf("%d", &id) == 1) {25 lock.l_type = F_WRLCK;26 lock.l_whence = SEEK_SET;27 lock.l_start = (id-START_ID)*sizeof(record);28 lock.l_len = sizeof(record);29 if (fcntl(fd,F_SETLKW, &lock) == -1) { /* 쓰기 잠금 */30 perror(argv[1]);31 exit(3);32 }33

14

Page 15: 13 장 프로세스 사이의 통신

wrlock.c34 lseek(fd, (long) (id-START_ID)*sizeof(record), SEEK_SET);35 if ((read(fd, (char *) &record, sizeof(record)) > 0) && (record.id != 0))37 printf(" 이름 :%s\t 학번 :%d\t 점수 :%d\n",38 record.name, record.id, record.score);39 else printf(" 레코드 %d 없음 \n", id);4041 printf(" 새로운 점수 : ");42 scanf("%d", &record.score);43 lseek(fd, (long) -sizeof(record), SEEK_CUR);44 write(fd, (char *) &record, sizeof(record));4546 lock.l_type = F_UNLCK;47 fcntl(fd, F_SETLK, &lock); /* 잠금 해제 */48 printf("\n 수정할 학생의 학번 입력 :");49 }51 close(fd);52 exit(0);53 }

15

Page 16: 13 장 프로세스 사이의 통신

권고 잠금과 강제 잠금 권고 잠금 (advisory locking)

지금까지 살펴본 잠금 : 잠금을 할 수 있지만 강제되지는 않음 .

즉 이미 잠금이 된 파일의 영역에 대해서도 잠금 규칙을 무시하고 읽거나 쓰는 것이 가능하다 .

모든 관련 프로세스들이 자발적으로 잠금 규칙을 준수 .

강제 잠금 (mandatory locking) 커널이 잠금 규칙을 강제 이미 잠금이 된 파일 영역에 대해 잠금 규칙을 무시하고

읽거나 쓰는 것이 불가능하다 . 시스템의 부하가 증가

16

Page 17: 13 장 프로세스 사이의 통신

강제 잠금 강제 잠금을 하는 방법

해당 파일에 대해 set-group-ID 비트를 설정하고 group-execute 비트를 끄면 된다

$ chmod 2644 mandatory.txt$ ls -l mandatory.txt-rw-r-lr-- 1 chang faculty 160 1 월 31 일 11:48 stdb1

강제 잠금 규칙

17

대상영역의현재잠금

상태

넌블로킹디스크립터 블로킹디스크립터

읽기 쓰기 읽기 쓰기

읽기잠금

블로킹

쓰기잠금

블로킹 블로킹

Page 18: 13 장 프로세스 사이의 통신

file_lock.c#include <stdio.h>

#include <fcntl.h>

int main(int argc, char **argv) {

static struct flock lock;

int fd, ret, c;

if (argc < 2) {

fprintf(stderr, " 사용법 : %s 파일 \n", argv[0]);

exit(1);

}

fd = open(argv[1], O_WRONLY);

if (fd == -1) {

printf(" 파일 열기 실패 \n");

exit(1);

}

lock.l_type = F_WRLCK;

lock.l_start = 0;

lock.l_whence = SEEK_SET;

lock.l_len = 0;

lock.l_pid = getpid();

ret = fcntl(fd, F_SETLKW, &lock);

if(ret == 0) { // 파일 잠금 성공하면

c = getchar();

}

}

18

Page 19: 13 장 프로세스 사이의 통신

13.2 파이프

19

Page 20: 13 장 프로세스 사이의 통신

파이프 원리 $ who | sort

파이프 물을 보내는 수도 파이프와 비슷하다 . 한 프로세스는 쓰기용 파일 디스크립터를 이용하여 파이프에

데이터를 보내고 ( 쓰고 ) 다른 프로세스는 읽기용 파일 디스크립터를 이용하여 그

파이프에서 데이터를 받는다 ( 읽는다 ). 한 방향 (one way) 통신

20

Page 21: 13 장 프로세스 사이의 통신

파이프 생성 파이프는 두 개의 파일 디스크립터를 갖는다 . 하나는 쓰기용이고 다른 하나는 읽기용이다 .

21

#include <unistd.h>

int pipe(int fd[2])

파이프를 생성한다 . 성공하면 0 을 실패하면 -1 를 리턴한다 .

Page 22: 13 장 프로세스 사이의 통신

파이프 사용법(1) 한 프로세스가 파이프를 생성한다 .

(2) 그 프로세스가 자식 프로세스를 생성한다 .

(3) 쓰는 프로세스는 읽기용 파이프 디스크립터를 닫는다 .

읽는 프로세스는 쓰기용 파이프 디스크립터를 닫는다 .

(4) write()와 read() 시스템 호출을 사용하여 파이프를 통해 데이터를 송수신한다 .

(5) 각 프로세스가 살아 있는 파이프 디스크립터를 닫는다 .

22

Page 23: 13 장 프로세스 사이의 통신

파이프 사용법 자식 생성 후 자식에서 부모로 보내기

23

Page 24: 13 장 프로세스 사이의 통신

pipe.c1 #include <unistd.h>

2 #define MAXLINE 100

3 /* 파이프를 통해 자식에서 부모로 4 데이터를 보내는 프로그램 */

5 int main( )

6 {

7 int n, length, fd[2];

8 int pid;

9 char message[MAXLINE],

line[MAXLINE];

10

11 pipe(fd); /* 파이프 생성 */

12

13 if ((pid = fork()) == 0) {

/* 자식 프로세스 */

14 close(fd[0]);

15 sprintf(message, "Hello from PID %d\n", getpid());

16 length = strlen(message)+1;

17 write(fd[1], message, length);

18 } else { /* 부모 프로세스 */

19 close(fd[1]);

20 n = read(fd[0], line, MAXLINE);

21 printf("[%d] %s", getpid(), line);

22 }

23

24 exit(0);

25 }

24

Page 25: 13 장 프로세스 사이의 통신

pexec1.c1 #include <stdio.h>

2 #include <unistd.h>

3 #define MAXLINE 100

4

5 /* 파이프를 통해 자식에서 실행되는명령어 출력을 받아 프린트 */

6 int main(int argc, char* argv[])

7 {

8 int n, pid, fd[2];

9 char line[MAXLINE];

10

11 pipe(fd); /* 파이프 생성 */

12

13 if ((pid = fork()) == 0) { // 자식 프로세스 14 close(fd[0]);

15 dup2(fd[1],1);

16 close(fd[1]);

17 execvp(argv[1], &argv[1]);

18 } else { // 부모 프로세스 19 close(fd[1]);

20 printf(" 자식 프로세스로부터 받은 결과 \n");

21 while ((n = read(fd[0], line, MAXLINE))> 0)

22 write(STDOUT_FILENO, line, n);

23 }

24

25 exit(0);

26 }

25

Page 26: 13 장 프로세스 사이의 통신

popen() 자식 프로세스에게 명령어를 실행시키고 그 출력 ( 입력 ) 을 파이프를

통해 받는 과정을 하나의 함수로 정의

fp = popen(command, "r"); fp = popen(command, “w");

26

#include <stdio.h>FILE *popen(const char *command, const char *type);성공하면파이프를위한파일포인터를실패하면을리턴한다int pclose(FILE *fp);성공하면 command 명령어의종료상태를실패하면을리턴한다

Page 27: 13 장 프로세스 사이의 통신

pexec2.c

#include <stdio.h>#define MAXLINE 100/* popen() 함수를 이용해 자식에서 실행되는 명령어 출력을 받아 프린트 */int main(int argc, char* argv[]){ char line[MAXLINE]; FILE *fpin; if ((fpin = popen(argv[1],"r")) == NULL) { perror("popen 오류 "); exit(1); } printf(" 자식 프로세스로부터 받은 결과 \n"); while (fgets(line, MAXLINE, fpin)) fputs(line, stdout); pclose(fpin); exit(0);}

27

Page 28: 13 장 프로세스 사이의 통신

13.3 이름 있는 파이프

28

Page 29: 13 장 프로세스 사이의 통신

이름 있는 파이프 (named pipe) ( 이름 없는 ) 파이프

이름이 없으므로 부모 자식과 같은 서로 관련된 프로세스 사이의 통신에만 사용될 수 있었다 .

이름 있는 파이프 다른 파일처럼 이름이 있으며 파일 시스템 내에 존재한다 . 서로 관련 없는 프로세스들도 공유하여 사용할 수 있다 .

29

Page 30: 13 장 프로세스 사이의 통신

이름 있는 파이프를 만드는 방법 p 옵션과 함께 mknod 명령어

$mknod myPipe p$chmod ug+rw myPipe$ls -l myPipeprw-rw-r-- 1 chang faculty 0 4 월 11 일 13:03 myPipe

mkfifo() 시스템 호출

30

#include <sys/types.h>

#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);

이름 있는 파이프를 생성한다 . 성공하면 0 을 실패하면 -1 을

리턴한다 .

Page 31: 13 장 프로세스 사이의 통신

npreader.c#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#define MAXLINE 100

/* 이름 있는 파이프를 통해 읽은 내용을 프린트한다 . */

int main( )

{

int fd;

char str[MAXLINE];

unlink("myPipe");

mkfifo("myPipe", 0660);

fd = open("myPipe", O_RDONLY);

while (readLine(fd, str))

printf("%s \n", str);

close(fd);

return 0;

}

int readLine(int fd, char *str)

{

int n;

do {

n = read(fd, str, 1);

} while (n > 0 && *str++ != NULL);

return (n > 0);

}

31

Page 32: 13 장 프로세스 사이의 통신

npwriter.c#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#define MAXLINE 100

/* 이름 있는 파이프를 통해 메시지를 출력한다 . */

int main( )

{

int fd, length, i

char message[MAXLINE];

sprintf(message, "Hello from PID %d", getpid());

length = strlen(message)+1;

do {

fd = open("myPipe", O_WRONLY);

if (fd == -1) sleep(1);

} while (fd == -1);

for (i = 0; i <= 3; i++) {

write(fd, message, length);

sleep(3);

}

close(fd);

return 0;

}

32

Page 33: 13 장 프로세스 사이의 통신

핵심 개념 한 레코드 혹은 파일에 대한

읽기 잠금은 여러 프로세스가 공유할 수 있지만 쓰기 잠금은 공유할 수 없으며 한 프로세스만 가질 수 있다 .

파이프는 두 개의 파일 디스크립터를 갖는다 .

하나는 쓰기용이고 다른 하나는 읽기용이다 .

이름 있는 파이프는 서로 관련 없는 프로세스들도 공유하여 사용할 수 있다 .

33