13장 프로세스 사이의 통신.

Slides:



Advertisements
Similar presentations
12장 프로세스.
Advertisements

6 레이스 컨디션.
인공지능실험실 석사 2학기 이희재 TCP/IP Socket Programming… 제 11장 프로세스간 통신 인공지능실험실 석사 2학기 이희재
13장 소켓.
Linux System Programming
제2부 시스템 프로그래밍 파일 및 입출력 2011 가을 숙명여대 창병모 © 숙대 창병모.
Department of Computer Engineering
9 파이프.
Signal & Inter-Process Communication
08. 디바이스 드라이버의 읽기와 쓰기 김진홍
Linux System Programming
데이터 파일 C 데이터 파일과 스트림(Stream) 텍스트 파일 처리
제2장. 파일 입출력 (File I/O) © 숙대 창병모.
Department of Computer Science and Engineering
조 병 규 Software Quality Lab. 한국교통대학교
Part 14 파일 입출력 ©우균, 창병모 ©우균, 창병모.
14장 소켓.
제 12장 I/O멀티플렉싱(Multiplexing)
Department of Computer Engineering
인공지능실험실 석사 2학기 이희재 TCP/IP Socket Programming… 제 7장 소켓 연결의 우아한 종료 인공지능실험실 석사 2학기 이희재
양방향 파이프의 활용 양방향 통신 파이프는 기본적으로 단방향이므로 양방향 통신을 위해서는 파이프를 2개 생성한다.
12장 파이프.
fork로 생성한 자식 프로세스에서 exec 함수군을 호출
07. 디바이스 드라이버의 초기화와 종료 김진홍
11장. 포인터 01_ 포인터의 기본 02_ 포인터와 Const.
12장 프로세스.
고급 입출력 함수 School of Electronics and Information. Kyung Hee University.
9장 파일 입출력.
Signal & Inter-Process Communication
프로세스 생성[1] 프로그램 실행 : system(3) #include <stdlib.h>
시스템 호출 read , write의 효율성 lseek test example – test1.c 실습 – 연습문제 2.8
Linux/UNIX Programming
파이프와 exec 시스템 호출 (ls | wc)
파일 기술자 복사 파일 기술자 복사 : dup(2) 파일 기술자 복사 : dup2(3)
12장 파일처리와 매크로 파일 입출력 함수 문자 입출력 함수 라인 입출력 함수 불록 입출력 함수 매크로.
8 메모리 매핑.
파일 기술자 파일 기술자 현재 열려있는 파일을 구분하는 정수값 저수준 파일 입출력에서 열린 파일을 참조하는데 사용
(ioctl, mmap, fsync&flush)
4장 파일.
임베디드 실습 # LED, 7’Segment 제어
6장 파일 및 레코드 잠금.
Linux/UNIX Programming
11장 파일.
메시지 큐[5] – test1.c 메시지 제어: msgctl(2) #include <sys/msg.h>
Department of Computer Engineering
13장 고급 입출력 함수 박사 4학기 최 성자.
TCP/IP Socket Programming…
FILE I/O 번째주 Dept. of Computer Science & Engineering
10장 C 표준 파일 입출력 子曰 學而時習(실습?)之 不亦悅乎.
Department of Computer Engineering
Signal & Inter-Process Communication
Memory & Data Management.
24장. 파일 입출력.
School of Electronics and Information. Kyung Hee University.
컴퓨터 프로그래밍 기초 - 10th : 포인터 및 구조체 -
조 병 규 Software Quality Lab. 한국교통대학교
Linux/UNIX Programming
Signal & Inter-Process Communication
Homework 7… 마지막 수업시간까지 (실습) 매개변수로 입력 받아 처리할 수 있도록 수정해 보세요
3. 모듈 (5장. 모듈).
구조체(struct)와 공용체(union)
실습과제 1번 생성된 파일 basic.txt를 프로젝트 폴더에서 메모장으로 열고 내용을 확인
9 파이프.
Department of Computer Engineering
06. 디바이스의 등록과 해제 김진홍
Signal & Inter-Process Communication
C 13장. 입출력 라이브러리 #include <stdio.h> int main(void) { int num;
3장 파일 다루기 한빛미디어(주).
개정판 누구나 즐기는 C언어 콘서트 제12장 파일 입출력 출처: pixabay.
Signal & Inter-Process Communication
Presentation transcript:

13장 프로세스 사이의 통신

13.1 파일 및 레코드 잠금

파일 및 레코드 잠금의 원리 어떻게 프로세스 사이에 데이터를 주고받을 수 있을까? 문제점 한 프로세스가 파일에 쓴 내용을 다른 프로세스가 읽음 문제점 한 프로세스가 파일 내용을 수정하는 동안에 다른 프로세스가 그 파일을 읽는 경우 두 개의 프로세스가 하나의 파일에 동시에 접근하여 데이터를 쓰는 경우

잠금(lock) 파일 혹은 레코드(파일의 일부 영역) 잠금 한 프로세스가 그 영역을 읽거나 수정할 때 다른 프로세스의 접 근을 제한한다 잠금된 영역에 한 번에 하나의 프로세스만 접근한다 특히 레코드에 쓰기를 할 경우 대상 레코드에 대해 잠금을 해서 다른 프로세스가 접근하지 못하게 해야 한다

잠금이 필요한 예 잠금 없음 잠금 사용 (1) 프로세스 A가 잔액을 읽는다: 잠금이 필요한 예 잠금 없음 (1) 프로세스 A가 잔액을 읽는다: 잔액 100만원 (2) 프로세스 B가 잔액을 읽는다: 잔액 100만원 (3) 프로세스 B가 잔액에 입금액을 더 하여 레코드를 수정한다: 잔액 120만원 (4) 프로세스 A가 잔액에 입금액을 더 하여 레코드를 수정한다: 잔액 110만원 잠금 사용 (1) 프로세스 A가 레코드에 잠금을 하고 잔액을 읽는다: 잔액 100만원 (2) 프로세스 A가 잔액에 입금액을 더하 여 레코드를 수정하고 잠금을 푼다: 잔액 110만원 (3) 프로세스 B가 레코드에 잠금을 하고 잔액을 읽는다: 잔액 110만원 (4) 프로세스 B가 잔액에 입금액을 더하 여 레코드를 수정하고 잠금을 푼다: 잔액 130만원

잠금 구현 fcntl( ) 함수 잠금의 종류 파일 및 레코드 잠금을 구현할 수 있다 F_RDLCK : 여러 프로세스가 공유 가능한 읽기 잠금 F_WRLCK : 한 프로세스만 가질 수 있는 배타적인 쓰기 잠금 대상 영역의 현재 잠금 상태 읽기 잠금 요청 쓰기 잠금 요청 잠금 없음 승인 하나 이상의 읽기 잠금 거절 하나의 쓰기 잠금

잠금 함수: fcntl() fd는 대상이 되는 파일 디스크립터 cmd flock 구조체 F_GETLK : 잠금 검사 F_SETLK : 잠금 설정 혹은 해제 F_SETLKW: 잠금 설정(블로킹 버전) 혹은 해제 flock 구조체 잠금 종류, 프로세스 ID, 잠금 위치 등 #include <sys/types.h> #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, struct flock *lock); cmd에 따라 잠금 검사 혹은 잠금 설정을 한다. 성공하면 0 실패하면 -1을 리턴한다.

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; // 프로세스 번호 };

잠금 예제 학생 레코드를 질의하는 프로그램: rdlock.c 학생 레코드를 수정하는 프로그램: wrlock.c 수정 프로그램에서 어떤 레코드를 수정하는 중에는 질의 프로그램에 서 그 레코드를 읽을 수 없도록 레코드 잠금을 이용하여 제한한다 프로그램에 대한 자세한 설명 : 교재 412-415 참조

rdlock.c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include "student.h" #define START_ID 1201001 /*잠금을 이용한 학생 데이터베이스 질의 프로그램*/ int main(int argc, char *argv[]) { int fd, id; struct student record; struct flock lock; if (argc < 2) { fprintf(stderr, "사용법 : %s 파일\n", argv[0]); exit(1); } if ((fd = open(argv[1], O_RDONLY)) == -1) { perror(argv[1]); exit(2); printf("\n검색할 학생의 학번 입력:"); while (scanf("%d", &id) == 1) { lock.l_type = F_RDLCK; lock.l_whence = SEEK_SET; lock.l_start = (id-START_ID)*sizeof(record); lock.l_len = sizeof(record); if (fcntl(fd,F_SETLKW, &lock) == -1) { /*읽기 잠금*/ perror(argv[1]); exit(3); } lseek(fd, (id-START_ID)*sizeof(record), SEEK_SET); if ((read(fd, (char *) &record, sizeof(record)) > 0) && (record.id != 0)) printf("이름:%s\t 학번:%d\t 점수:%d\n", record.name, record.id, record.score); else printf("레코드 %d 없음\n", id); lock.l_type = F_UNLCK; fcntl(fd,F_SETLK, &lock); /* 잠금 해제 */ close(fd); exit(0);

wrlock.c printf("\n수정할 학생의 학번 입력:"); while (scanf("%d", &id) == 1) { lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = (id-START_ID)*sizeof(record); lock.l_len = sizeof(record); if (fcntl(fd,F_SETLKW, &lock) == -1) { /*쓰기 잠금*/ perror(argv[1]); exit(3); } lseek(fd, (long) (id-START_ID)*sizeof(record), SEEK_SET); if ((read(fd, (char *) &record, sizeof(record)) > 0) && (record.id != 0)) printf("이름:%s\t 학번:%d\t 점수:%d\n", record.name, record.id, record.score); else printf("레코드 %d 없음\n", id); printf("새로운 점수: "); scanf("%d", &record.score); lseek(fd, (long) -sizeof(record), SEEK_CUR); write(fd, (char *) &record, sizeof(record)); lock.l_type = F_UNLCK; fcntl(fd, F_SETLK, &lock); /* 잠금 해제 */ close(fd); exit(0); #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include "student.h" #define START_ID 1201001 /*잠금을 이용한 학생 데이터베이스 수정 프로그램*/ int main(int argc, char *argv[]) { int fd, id; struct student record; struct flock lock; if (argc < 2) { fprintf(stderr, "사용법 : %s 파일 \n", argv[0]); exit(1); } if ((fd = open(argv[1], O_RDWR)) == -1) { perror(argv[1]); exit(2);

권고 잠금과 강제 잠금 권고 잠금(advisory locking) 강제 잠금(mandatory locking) 지금까지 살펴본 잠금은 잠금을 할 수 있지만 강제되지는 않는다 즉 이미 잠금이 된 파일의 영역에 대해서도 잠금 규칙을 무시하 고 읽거나 쓰는 것이 가능하다 모든 관련 프로세스들이 자발적으로 잠금 규칙을 준수한다 강제 잠금(mandatory locking) 커널이 잠금 규칙을 강제 이미 잠금이 된 파일 영역에 대해 잠금 규칙을 무시하고 읽거나 쓰는 것이 불가능하다 시스템의 부하가 증가

강제 잠금 강제 잠금을 하는 방법 강제 잠금 규칙 해당 파일에 대해 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 강제 잠금 규칙 대상 영역의 현재 잠금 상태 넌블로킹 디스크립터 블로킹 디스크립터 읽기 쓰기 읽기 잠금 OK EAGAIN 블로킹 쓰기 잠금

filelock.c #include <stdio.h> #include <stdlib.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"); 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();

13.2 파이프

파이프 원리 $ who | sort 파이프 물을 보내는 수도 파이프와 비슷 한 프로세스는 쓰기용 파일 디스크립터를 이용하여 파이프에 데 이터를 보내고(쓰고) 다른 프로세스는 읽기용 파일 디스크립터를 이용하여 그 파이프 에서 데이터를 받는다(읽는다) 한 방향(one way) 통신

파이프 생성 파이프는 두 개의 파일 디스크립터를 갖는다 하나는 쓰기용이고 다른 하나는 읽기용이다 #include <unistd.h> int pipe(int fd[2]) 파이프를 생성한다. 성공하면 0을 실패하면 -1를 리턴한다.

파이프 사용법 (1) 한 프로세스가 파이프를 생성한다 (2) 그 프로세스가 자식 프로세스를 생성한다 (3) 쓰는 프로세스는 읽기용 파이프 디스크립터를 닫는다 읽는 프로세스는 쓰기용 파이프 디스크립터를 닫는다 (4) write()와 read() 시스템 호출을 사용하여 파이프를 통해 데이터를 송수신한다 (5) 각 프로세스가 살아 있는 파이프 디스크립터를 닫는다

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

pipe.c #include <unistd.h> #define MAXLINE 100 /* 파이프를 통해 자식에서 부모로 데 이터를 보내는 프로그램 */ int main( ) { int n, length, fd[2]; int pid; char message[MAXLINE], line[MAXLINE]; pipe(fd); /* 파이프 생성 */ if ((pid = fork()) == 0) { /* 자식 프로세스 */ close(fd[0]); sprintf(message, "Hello from PID %d\n", getpid()); length = strlen(message)+1; write(fd[1], message, length); } else { /* 부모 프로세스 */ close(fd[1]); n = read(fd[0], line, MAXLINE); printf("[%d] %s", getpid(), line); } exit(0);

pexec1.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define MAXLINE 100 /* 파이프를 통해 자식에서 실행되는 명령어 출력을 받아 프린트 */ int main(int argc, char* argv[]) { int n, pid, fd[2]; char line[MAXLINE]; pipe(fd); /* 파이프 생성 */ if ((pid = fork()) == 0) { //자식 프로세스 close(fd[0]); dup2(fd[1],1); close(fd[1]); execvp(argv[1], &argv[1]); } else { // 부모 프로세스 printf("자식 프로세스로부터 받은 결과\n"); while ((n = read(fd[0], line, MAXLINE))> 0) write(STDOUT_FILENO, line, n); } exit(0);

popen() fp = popen(command, "r"); fp = popen(command, “w"); 자식 프로세스에게 명령어를 실행시키고 그 출력(입력)을 파이프를 통 해 받는 과정을 하나의 함수로 정의 fp = popen(command, "r"); fp = popen(command, “w"); #include <stdio.h> FILE *popen(const char *command, const char *type); 성공하면 파이프를 위한 파일 포인터를 실패하면 NULL을 리턴한다. int pclose(FILE *fp); 성공하면 command 명령어의 종료 상태를 실패하면 -1을 리턴한다.

pexec2.c #include <stdio.h> #include <stdlib.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);

13.3 이름 있는 파이프

이름 있는 파이프(named pipe) (이름 없는) 파이프 이름 있는 파이프 이름이 없으므로 부모 자식과 같은 서로 관련된 프로세스 사이 의 통신에만 사용될 수 있었다 이름 있는 파이프 다른 파일처럼 이름이 있으며 파일 시스템 내에 존재한다 서로 관련 없는 프로세스들도 공유하여 사용할 수 있다

이름 있는 파이프를 만드는 방법 p 옵션과 함께 mknod 명령어 mkfifo() 시스템 호출 $mknod myPipe p $chmod ug+rw myPipe $ls -l myPipe prw-rw-r-- 1 chang faculty 0 4월 11일 13:03 myPipe mkfifo() 시스템 호출 #include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode); 이름 있는 파이프를 생성한다. 성공하면 0을 실패하면 -1을 리턴한다.

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

npwriter.c #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <string.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;

핵심 개념 한 레코드 혹은 파일에 대한 파이프는 두 개의 파일 디스크립터를 갖는다 하나는 쓰기용이고 다른 하나는 읽기용이다 읽기 잠금은 여러 프로세스가 공유할 수 있지만 쓰기 잠금은 공유할 수 없으며 한 프로세스만 가질 수 있다 파이프는 두 개의 파일 디스크립터를 갖는다 하나는 쓰기용이고 다른 하나는 읽기용이다 이름 있는 파이프는 서로 관련 없는 프로세스들도 공유하여 사용할 수 있다