제 2 부프로세스관리 (Process Management) 프로세스» 실행중인프로그램 (program in execution) CPU time, memory, files, I/O devices 등자원요구» 시스템의작업단위 (the unit of work)» 종류 1. 사용자프로세스 (user process) - user code 실행 2. 시스템프로세스 (system process) - system code 실행 프로세스관리» 사용자프로세스와시스템프로세스의생성과삭제» 프로세스스케줄링» 프로세스들의동기화기법지원3» 프로세스들의통신지원» 프로세스들의교착상태 (deadlock) 처리 3.1
Chapter 3. 프로세스관리 (Process Management) 1. 프로세스개념 (Process Concept) 2. 프로세스스케줄링 (Process Scheduling) 3. 프로세스에대한연산 (Operation on Processes) fork + exec 4. 프로세스협조 (Cooperating Processes) 생산자 - 소비자문제 5. 프로세스간통신 (Interprocess Communication) 6. IPC 시스템의사례 (Examples of IPC Systems) 7. 클라이언트서버환경에서의통신 (Communication in Client- Server Systems) 3.2
Chapter 3. 프로세스개념 (Process Concept) Questions of the day 1. 프로세스는 중인프로그램? 2. Linux 는프로세스를표현하는 PCB(Process Control Block) 구조체이름은? 3. Unix/Linux 프로세스를생성하는시스템호출은? 4. 프로세스스케줄링이사용하는큐는? 5. 프로세스의문맥 (context) 은어디에저장? 6. 컴퓨터시스템안에서발견할수있는생산자 - 소비자관계에있는프로세스들의예는? 7. 유한버퍼생산자 - 소비자문제 (bounded buffer producerconsumer problem) 해결책은? 3.3
프로세스개념 (Process Concept) 예전 1 program 실행 오늘날 multiple program 의동시실행 프로세스 (The Process)» 프로그램코드 + 현재활동 (Current activity) PC(Program Counter) 레지스터값 스택 (stack) : 서브루틴, 매개변수, 복귀주소, 임시변수등 데이터부분 (data section) : 전역변수 프로세스상태 (Process State)» 생성 (new)» 수행 (running) : CPU 가실행» 대기 (waiting) : I/O 완료나 signal 기다림» 준비 (ready) : Processor 를받을준비가됨» 종료 (terminated) 3.4
프로세스상태 (Process State) 3.5
Process in Memory 3.6
( 참고 ) Linux 가상메모리구조 하나의태스크마다 4GB 주소공간을할당» 각태스크에게 3GB 할당» 나머지 1GB 는모든태스크들의공통영역으로서커널공간으로할당 $ cat /proc/1/maps BSS(Block Started by Symbol) 3.7
( 참고 ) Linux 메모리관리자료구조 task_struct 구조체내의 struct mm_struct *mm» /usr/src/kernels/linux-2.6.35.6/include/linux/sched.h (1256 행 Fedora Linux 2.6.38.6)» /usr/src/kernels/linux-2.6.35.6/include/linux/mm_types.h (222 행, 131 행 )» 메모리디스크립터 3.8
프로세스개념 (Process Concept) 프로세스제어블럭 (Process Control Block) /proc 참고» 각프로세스는 PCB 로표현됨» PCB Solaris 10 Unix: /usr/include/sys/proc.h 110 행 Fedora Linux: /usr/src/kernels/linux-2.6.38.6/include/linux/sched.h 1193 행 Ubuntu task_struct 구조체는어디에? 프로세스상태 : new, ready, running, waiting, halted 프로그램카운터 : next instruction 의주소 CPU 레지스터들 : accumulator, index register, stack pointers, 범용 registers, condition-code CPU 스케줄정보 : priority, pointers to scheduling queues 메모리관리정보 : base and limit registers, page tables, segment tables 계정정보 : time used, time limits, account numbers, job#, process# 입출력상태정보 : I/O devices list allocated to the process, list of open files 스레드 (Threads)» a process = a single thread of execution (one task)» 많은현대 OS 들이 multiple threads of control (multitasks at a time) 지원 3.9
Process Control Block (PCB) 3.10
( 참고 ) Linux task_struct 구조체 구조체를통한정보관리» 프로세스가생성되면 task_struct 구조체를통해프로세스의모든정보를저장하고관리 모든태스크들에게하나씩할당 /usr/src/kernels/linux-2.6.38.6/include/linux/sched.h (1193 행 ) 태스크 ID, 상태정보, 가족관계, 명령, 데이터, 시그널, 우선순위, CPU 사용량및파일디스크립터등생성된태스크의모든정보를가짐 alloc_task_struct 매크로를통해커널영역의메모리에서 8KB 를할당받아프로세스디스크립터와커널스택의자료를저장 current : 현재실행되고있는태스크를가리키는변수 /usr/src/kernels/inux- 2.6.38.6/arch/x86/include/asm/current.h (17 행 ) 커널스택과프로세스디스크립터 3.11
( 참고 ) Linux task_struct 구조체 태스크관계와관련된변수들 struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;» p_opptr 과 p_pptr : 부모태스크 p_oppr : Original Parent» p_cptr : 자식, p_ysptr : 아우, p_osptr : 형 struct task_struct *next_task, *prev_task;» 커널에존재하는모든태스크들은원형이중연결리스트로연결 SET_LINKS : 리스트에추가하는매크로 REMOVE_LINK : 리스트서삭제하는매크로 task_struct 구조체 3.12
프로세스스케줄링 (Process Scheduling) 스케줄링큐 (Scheduling Queues)» 작업큐 (job queue) : memory 할당기다리는큐 (disk 에서 )» 준비큐 (ready queue) : CPU 에할당기다리는큐» 장치큐 (device queue() : 입출력기다리는큐» 큐잉도표 (queueing diagram) : 그림 3.7 스케줄러 (Schedulers)» 장기스케줄러 (long-term scheduler, job scheduler) pool memory(degree of multiprogramming) Unix 같은시분할시스템에는없음» 단기스케줄러 (short-term scheduler, CPU scheduler) CPU 할당 : must be very fast» 중기스케줄러 (medium-term scheduler) swapping» degree of multiprogramming 을줄임» memory backing store 3.13
준비큐와다양한입출력장치큐 3.14
프로세스스케줄링을표현하는큐잉도표 3.15
큐잉도표에중기스케줄링 (Medium Term Scheduling) 추가 3.16
프로세스스케줄링 (Process Scheduling) 문맥교환 (Context Switch)» CPU가한 process에서다른 process로 switch될때 save the state of the old process : CPU와메모리상태 (PCB정보) load the saved state for new process : CPU와메모리상태 (PCB정보)» pure overhead : performance bottleneck threads로해결» context-switch time : 1-1000microsecond» address space 보존방법 : memory 관리기법에좌우 3.17
한프로세스에서다른프로세스로의 CPU Switch 3.18
프로세스에대한오퍼레이션 (Operations on Processes) 프로세스생성 (Process Creation)» 프로세스생성시스템호출 : fork, exec, CreateProcess, etc. 부모프로세스 자신프로세스 : 사용자원을부모프로세스의자원 (memory, files) 공유» 새프로세스생성후부모는 계속실행 모든자식이끝날때까지기다림 : wait system call로 3.19
전형적인 UNIX System 의프로세스트리 $ ps ef more $ ps ax more 3.20
A tree of processes on a typical Solaris Q: Linux 의 1 번프로세스는? 3.21
프로세스에대한오퍼레이션 (Operations on Processes)» 새프로세스의 2 모델 ( 자식의주소공간관점에서본 ) 1) 자식은부모의것을복제 : fork 2) 자식은자신의새프로그램을가짐 : fork+exec 군» Unix 의예 : fork + exec 프로그램 (forkexecl.c & forkexecv.c 참조 ) 1) fork : 자식 process 생성, 모든 process 는 PID(Process identifier) 를가짐 2) fork + exec : 호출하는프로세스의기억장소에새프로그램 load» execl : 문자형인수포인터들 execl( /bin/ls, ls, -l, NULL);» execv : 인수배열의포인터 char *av[3]; av[0] = ls ; av[1] = -l ; av[2] = (char *)0; execv( /bin/ls, av); 3.22
프로세스에대한오퍼레이션 (Operations on Processes) 프로세스종료 (Process Termination)» exit 시스템종료 계산결과는부모에게 Return 메모리 ( 물리적 / 가상적 ), 오픈한화일, I/O 버퍼를 OS 에게돌려줌» abort 시스템호출 부모만호출 ( 그렇지않으면서로죽이는일생김 )» 실행종료이유 자식이할당된자원을초과사용할때 자식의 task 가더이상필요없을때 부모가종료될때 DEC VMS 또는 Unix 계단식 (cascading) 종료» 부모종료 OS 가모든자식종료» ( 예 ) Unix (mystatus.c 참조 ) exit system call 로프로세스종료 wait system call : return 값 = 종료하는자식의 pid wait(&status) /* int status */» status : 자식이 exit 으로종료될때의상태정보 정상종료경우 : 하위 8bits 는 0, 상위 8bits 는 exit status( 자식프로세스가 exit 명령으로전달한값 ), signal 로종료된경우 : 하위 8bits 는 signal 번호, 상위 8bits 는 0» ( 상위 8 비트추출 ) status >> 8; status &= 0xFF; 3.23
(Lab.3) 프로세스생성과종료 1. (Unix/Linux) One, Two 출력하는 onetwo.c 코딩, 컴파일, 실행 2. (Unix/Linux) n 개 fork 예제 nfork.c 코딩, 컴파일, 실행 3. (Unix/Linux) 시스템호출 execl() 을이용하여 ls 프로그램을실행시키는 forkexecl.c 코딩, 컴파일, 실행 4. (Unix/Linux) 시스템호출 execv() 를이용하여 ls 프로그램을실행시키는 forkexecv.c 코딩, 컴파일, 제출 실습당일 24 시까지 5. (Unix/Linux) Shell 을느끼는 background.c 코드분석, 컴파일, 실행 6. (Unix/Linux) mystatus.c & myexit.c 코드분석, 컴파일, 실행 7. (Windows) Win32 API 를이용한새프로세스생성 ( 교재 p126) 코딩, 컴파일, 실행 4 번만제출 ( 집에서도접속가능합니다 )» 2 Electronic versions: cyber.incheon.ac.kr (Lab.3) 에제출 117.16.244.59 지정디렉토리 /home/os2013hwa 또는 os2013hwb 에자기학번의디렉토리만들고그곳에소스파일과실행파일복사 3.24
1. fork 시스템호출 : onetwo.c printf( One\n ); pid = fork(); printf(two\n ); PC #include <stdio.h> main() { int pid; printf("one\n"); pid = fork(); printf("two\n"); 1. getpid() 2. fork(); 추가 A fork $ gcc onetwo.c o onetwo BEFORE AFTER printf( One\n ); pid=fork(); printf( Two\n ); PC printf( One\n ); pid = fork(); printf( Two\n ); PC A 3.25
2. n 개의 fork() 예제 nfork.c #include <stdlib.h> #include <stdio.h> int main() { int pid1, pid2; if ((pid1=fork()) == 0) { printf("[child 1] : Hello, world! pid=%d\n", getpid()); //exit(0); printf("[parent] : Hello, world! pid=%d\n", getpid()); if ((pid2=fork()) == 0) { printf("[child 2] : Hello, world! pid=%d\n", getpid()); //exit(0); 1. 자식 process 개수는? 2. exit 적용후자식 process 개수는? 3.26
3. fork 와 exec 호출의조합 pid = fork(); PC A BEFORE FORK AFTER FORK wait((int*)0); PC execl( /bin/ls ); PC A B AFTER FORK AFTER EXEC /* first line of ls */ PC wait((int*)0); PC A 3.27 B (now runs ls)
3.& 4. fork() 로새프로세스를생성하는 forkexec.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> void main(int argc, char *argv[]) { int pid; /* fork another process */ pid = fork(); if(pid < 0) { /* error occurred */ fprintf(stderr, "Fork Failed"); exit(-1); else if (pid == 0) { /* child process */ execl("/bin/ls", "ls", "-l", NULL); else { /* parent process */ wait(null); printf("child Complete\n"); exit(0); 3.28 execv char *av[3]; av[0]="ls"; av[1]="-l"; av[2]=(char *)0; execv("/bin/ls", av); execlp, execvp 쉘환경변수 PATH 를따름 execlp("ls", " ls ", " -l ", (char *)0); execvp(" ls ", av);
5. Shell 을느끼는 background.c 후면처리 (background processing)» 코드 $ cat background.c #include <stdio.h> main (int argc, char *argv[]) { if (fork () == 0) /* Child */ {» 실행 execvp (argv[1], &argv[1]); /* Execute other program */ fprintf (stderr, "Could not execute %s\n", argv[1]); $ gcc background.c o background $./background ls -l 3.29
6. exit 예제 mystatus.c & myexit.c $ cat mystatus.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> main () { int pid, status, childpid; printf ("I'm the parent process and my PID is %d\n", getpid ()); pid = fork (); /* Duplicate */ if (pid!= 0) /* Branch based on return value from fork () */ { $ cat myexit.c #include <stdio.h> #include <stdlib.h> main () { printf ("I'm going to exit with return code 33\n"); exit (33); printf ("I'm the parent process with PID %d and PPID %d\n", getpid (), getppid ()); childpid = wait (&status); /* Wait for a child to terminate. */ printf ("A child with PID %d, terminated with exit code low: %d, high: %d\n", childpid, (status & 0xFF), status >> 8); /* Linux */ else { printf ("I'm the child process with PID %d and PPID %d\n", getpid (), getppid ()); execlp ("ls", "ls", "-li", (char *)0); /* execlp ("myexit", "myexit", (char *)0); */ exit (42); /* Exit with a silly number */ printf ("PID %d terminates\n", getpid () ); 3.30
7. Win32 API 를이용한새프로세스생성 #include <Windows.h> #include <stdio.h> int main(void) { STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); if(!createprocess(null, // 명령어라인사용 { "C://Windows/System32//mspaint.exe", // 명령어라인 NULL, // 프로세스를상속하지말것 NULL, // 쓰레드핸들을상속하지말것 FALSE, // 핸들상속다제이블 0, // 생성플래그없음 NULL, // 부모환경블록사용 NULL, // 부모프로세스가존재하는디렉토리사용 &si, &pi)) fprintf(stderr, "Create Process Failed"); return -1; // 부모프로세스가자식프로세스가끝나기를기다림 WaitForSingleObject(pi.hProcess, INFINITE); printf("child Complete"); // 핸들닫기 CloseHandle(pi.hProcess); CloseHandle(pi.hThread); 3.31 실행오류나면 Visual Studio 의프로젝트속성 일반 문자집합을 [ 멀티바이트문자집합사용 ] 으로변경
프로세스협조 (Cooperating Processes) 프로세스협조하는이유» 정보공유 (information sharing)» 계산속도증가 (computation speedup) : parallel computing 으로» 모듈화 (modularity)» 편이성 (convenience) : parallel computing 으로 프로세스협조예 : 생산자 - 소비자 (producer-consumer) 문제» compiler : assembly code 생산» assembler : assembly code 소비, object code 생산» loader : object code 소비 생산자와소비자가동시에수행되려면 buffer 가필요 ( 동시수행을위해 ) 생산자와소비자의동기화필요 ( 생산되지않은자료소비하지않게 ) 생산자 - 소비자문제종류» 1. 무한버퍼 (unbounded-buffer) 생산자 - 소비자문제 생산자는항상생산, 소비자는소비할자료를기다릴수도» 2. 유한버퍼 (bounded-buffer) 생산자 - 소비자문제 버퍼가꽉차있으면생산자가대기, 버퍼가비어있으면소비자가대기 3.32
프로세스협조 (Cooperating Processes) 유한버퍼생산자-소비자문제 (bounded-buffer producer-consumer problem) 스레드 (LWP) 로하면효과적» Version 1: 공유메모리를이용한해결책 (3.4.1절)» Version 2: 메시지전달 (IPC) 을이용한해결책 (3.4.2절)» Version 3: 세마포어를이용한해결책 (6.6.1절)» Version 4: 세마포어와스레드를이용한해결책 (6장프로젝트 p266)» Version 5: Java synchronization을이용한해결책 3.33
Shared Memory count=3 in=0 out=0 count=0 in=0 out=0 count=2 in=2 out=0 2 0 count=0 in=0 out=0 count=1 in=0 out=2 1 count=1 in=1 out=0 count=2 in=0 out=1 3.34
Shared Memory count=3 in=0 out=0 count=0 in=0 out=0 count=2 in=2 out=0 2 0 count=0 in=0 out=0 count=1 in=0 out=2 1 count=1 in=1 out=0 count=2 in=0 out=1 3.35
공유메모리를이용하는생산자 - 소비자문제 import java.util.*; public class BoundedBuffer { public BoundedBuffer() { // buffer is initially empty count = 0; in = 0; out = 0; buffer = new Object[BUFFER_SIZE]; // producer calls this method public void enter(object item) { // The enter method // consumer calls this method public Object remove() { // The remove() method public static final int NAP_TIME = 5; private static final int BUFFER_SIZE = 3; private volatile int count; private int in; // points to the next free position private int out; //points to the next full position private Object[] buffer; 3.36
공유메모리시스템의생산자 enter() 메소드 public void enter(object item) { while (count == BUFFER_SIZE) ; // do nothing // add an item to the buffer ++count; buffer[in] = item; in = (in + 1) % BUFFER_SIZE; if (count == BUFFER_SIZE) System.out.printIt( Producer Entered + item + Buffer Full ); else count); System.out.printIt( Producer Entered + item + Buffer size = + 3.37
공유메모리시스템의소비자 remove() 메소드 public Oject remove() { Object item; while (count == 0) ; // do nothing // remove an item to the buffer --count; item = buffer[out]; out = (out + 1) % BUFFER_SIZE; if (count == 0) else System.out.printIt( Consumer Consumed + item + BufferEmpty ); System.out.printIt( Consumer Consumer + item + Buffer size = + count); 3.38
공유메모리시스템의 Consumer.java import java.util.*; public class Consumer extends Thread { public Consumer(BoundedBuffer b) { buffer = b; public void run() { Date message; while (true) { int sleeptime = (int) (BoundedBuffer.NAP_TIME * Math.random() ); System.out.println("Consumer sleeping for " + sleeptime + " seconds"); try { sleep(sleeptime*1000); catch(interruptedexception e) { // consume an item from the buffer System.out.println("Consumer wants to consume."); message = (Date)buffer.remove(); private BoundedBuffer buffer; 3.39
공유메모리시스템의 Producer.java import java.util.*; public class Producer extends Thread { public Producer(BoundedBuffer b) { buffer = b; public void run() { Date message; while (true) { int sleeptime = (int) (BoundedBuffer.NAP_TIME * Math.random() ); System.out.println("Producer sleeping for " + sleeptime + " seconds"); try { sleep(sleeptime*1000); catch(interruptedexception e) { // produce an item & enter it into the buffer message = new Date(); System.out.println("Producer produced " + message); buffer.enter(message); private BoundedBuffer buffer; 3.40
공유메모리시스템의 Server.java public class Server { public static void main(string args[]) { BoundedBuffer server = new BoundedBuffer(); // now create the producer and consumer threads Producer producerthread = new Producer(server); Consumer consumerthread = new Consumer(server); producerthread.start(); consumerthread.start(); 3.41
프로세스간통신 (Inter-Process Communication) 통신방식 한시스템에서둘다사용해도됨» 공유메모리방식 (shared-memory) 응용프로그램작성자가응용레벨에서통신기능제공 ( 예 ) 유한버퍼생산자 - 소비자문제 version 1» 메시지전달방식 (message-passing) IPC(interprocess-communication) 기능이용 : OS 가통신기능제공 ( 예 ) 유한버퍼생산자 - 소비자문제 version 2 IPC 기본구조 (Basic Structure)» IPC 기능의 2 연산 send (message) receive(message)» 프로세스 P 와 Q 가통신함 통신선이전재» 링크» 공유메모리» bus» network send/receive 연산 3.42
프로세스간통신 (Inter-Process Communication) 메시지시스템을구현하는기법들» 직접 (direct) 또는간접통신» 대칭 (symmetric) 또는비대칭 (symmetric) 통신» 자동 (automatic) 또는명시적 (explicit) 버퍼링» 복사 (copy) 에의한전송또는참고 (reference) 에의한전송» 고정길이 (fixed-sized) 또는가변길이 (variable-sized) 메시지 3.43
프로세스간통신 (Inter-Process Communication) 명칭부착 (Naming) 1) 직접통신 (Direct Communication) 대칭적통신 : 두프로세스 (sender/receiver) 가상대의이름을호출» Send(P, message) : 프로세스 P 에게메시지보냄» Receive(Q, message) : 프로세스 Q 로부터메시지받음 비대칭적통신 : sender 만 receiver 호출» Send(P, message) : 프로세스 P 에게메시지보냄» Receive(id, message) : 임의의프로세스로부터메시지받음 id = 통신이일어난순간메시지를보낸프로세스의이름으로설정됨 직접통신의단점» 프로세스이름바뀌면전부고쳐야 (limited modularity) 2) 간접통신 (Indirect Communication) mailbox(ports) 통해통신» send(a, message) : mailbox A 에메시지보냄» receive(a, message) : mailbox 로부터메시지받음 mailbox 의구현» 프로세스가 mailbox 소유» OS 가 mailbox 소유 3.44
프로세스간통신 (Inter-Process Communication) 동기화 (Synchronization)» Blocking send: 수신프로세스가메시지를받을때까지멈춤» Nonblocking send: 메시지보내고다른연산계속» Blocking receive: 메시지가있을때까지멈춤» Nonblocking receive: 올바른메시지이거나널메시지이거나상관하지않고받음 버퍼링 (Buffering)» 링크의메시지보유용량 Zero capacity : rendez-vous(no buffering) 동기적통신 Bounded capacity : 유한길이큐이용 자동버퍼링 Unbounded capacity : 무한길이큐이용 자동버퍼링 3.45
프로세스간통신 (Inter-Process Communication) 자동버퍼링경우» 보통비동기적통신 (asynchronous communication) 이일어남 보낸메시지도착여부모름 꼭알아야할경우 : 명시적통신 P : send(q, message); Q : receive(p, message); send(p, acknowledgment ); receive(q, message); 특별한경우» 비동기적통신 : 메시지보낸프로세스는절대로지연되지않음 보낸메시지미처받기전에새메시지보내면이전메시지유실될수있음 메시지유실방지위해복잡한명시적동기화필요» 동기적통신 : 메시지보낸프로세스는받았다는회신받을때까지기다림 Thoth OS : reply(p, message) 가메시지보낸프로세스와받는프로세스의수행재개 Sun RPC(Remote Procedure Call) 동기적통신 (synchronous communication)» sender : subroutine call reply올때까지블록됨» receiver : 계산결과를 reply (http://marvel.incheon.ac.kr의 Information 참조 ) 3.46
프로세스간통신 (Inter-Process Communication) 예외조건 (Exception Conditions)» centralized 또는 distributed system 에서고장발생시오류의회복 ( 예외조건 ) 필요» 프로세스종료 (Process Terminates) P 는종료된 Q 를기다림 P 는블록됨» P 종료» Q 종료사실을 P 에알림 P 가종료된 Q 에메시지보냄 Q 의 reply 기다려야할경우블록됨» 메시지유실 (Lost Messages) OS 가탐지및처리책임 sender 가탐지및처리책임 OS 가탐지, sender 가처리 훼손된메시지 (Scrambled Messages) 통신채널의잡음 (noise) 때문 보통 OS 가재전송 오류검사코드 (check sums, parity, CRC) 으로조사 3.47
Mailbox 를이용하는생산자 - 소비자문제 import java.util.*; public class MessageQueue { public MessageQueue() { queue = new Vector(); // This implements a nonblocking send public void send(object item) { queue.addelement(item); // This implements a nonblocking receive public Object receive() { Object item; if (queue.size() == 0) return null; else { item = queue.firstelement(); queue.removeelementat(0); return item; private Vector queue; 3.48
메시지시스템의생산자프로세스와소비자프로세스 생산자프로세스 MessageQueue mailbox; while (true) { Date message = new Date(); mailbox.send(message); 소비자프로세스 MessageQueue mailbox; while (true) { Date message =(Date) mailbox.receive(); if (message!=null) // consume the message 3.49
메시지시스템의 Producer.java import java.util.*; class Producer extends Thread { public Producer(MessageQueue m) { mbox = m; public void run() { Date message; while (true) { int sleeptime = (int) (Server.NAP_TIME * Math.random() ); System.out.println("Producer sleeping for " + sleeptime + " seconds"); try { sleep(sleeptime*1000); catch(interruptedexception e) { message = new Date(); System.out.println("Producer produced " + message); // produce an item & enter it into the buffer mbox.send(message); private MessageQueue mbox; 3.50
메시지시스템의 Consumer.java import java.util.*; class Consumer extends Thread { public Consumer(MessageQueue m) { mbox = m; public void run() { Date message; while (true) { int sleeptime = (int) (Server.NAP_TIME * Math.random() ); System.out.println("Consumer sleeping for " + sleeptime + " seconds"); try { sleep(sleeptime*1000); catch(interruptedexception e) { // consume an item from the buffer System.out.println("Consumer wants to consume."); message = (Date)mbox.receive(); if (message!= null) System.out.println("Consumer consumed " + message); private MessageQueue mbox; 3.51
메시지시스템의 Server.java import java.util.*; public class Server { public Server() { // first create the message buffer MessageQueue mailbox = new MessageQueue(); // now create the producer and consumer threads Producer producerthread = new Producer(mailBox); Consumer consumerthread = new Consumer(mailBox); producerthread.start(); consumerthread.start(); public static void main(string args[]) { Server server = new Server(); public static final int NAP_TIME = 5; 3.52
IPC 실례 : POSIX Shared Memory POSIX Shared Memory APIs» 프로세스는일차적으로 shmget (SHared Memory GET) 을이용하여공유메모리세스먼트생성 segment id = shmget(ipc PRIVATE, size, S_IRUSR S_IWUSR);» 프로세스는공유메모리에접근하기위해 shmat (SHared Memory ATtach) 를이용하여자신의주소공간 (address space) 에부착 shared memory = (char *) shmat(segment_id, NULL, 0);» 프로세스는반환된포인터가가리키는공유메모리에 read & write sprintf(shared memory, "Writing to shared memory");» 작업이끝나면프로세스는 shmdt (SHared Memory DeTach) 를이용하여자신의주소공간에서공유메모리를분리 shmdt(shared memory);» 마지막으로프로세스는 shmctl(shared Memory ConTroL operation) 에 IPC_RMID 플래그를지정하여공유메모리세그먼트를시스템에서제거 shmctl(segment_id, IPC_RMID, NULL); 3.53
/oshome/final-src/chap3/shm-posix.c #include <stdio.h> #include <sys/shm.h> #include <sys/stat.h> int main() { /* the identifier for the shared memory segment */ int segment_id; /* a pointer to the shared memory segment */ char* shared_memory; /* the size (in bytes) of the shared memory segment */ const int segment_size = 4096; /** allocate a shared memory segment */ segment_id = shmget(ipc_private, segment_size, S_IRUSR S_IWUSR); /** attach the shared memory segment */ shared_memory = (char *) shmat(segment_id, NULL, 0); printf("shared memory segment %d attached at address %p\n", segment_id, shared_memory); /** write a message to the shared memory segment */ sprintf(shared_memory, "Hi there!"); /** now print out the string from shared memory */ printf("*%s*\n", shared_memory); /** now detach the shared memory segment */ if ( shmdt(shared_memory) == -1) { fprintf(stderr, "Unable to detach\n"); /** now remove the shared memory segment */ shmctl(segment_id, IPC_RMID, NULL); return 0; 3.54
IPC 실례 : Mach 분산시스템을위한 OS 시스템호출, task 간정보전달을메시지로 port(= mailbox) task 생성 (kernel mailbox, notify mailbox) 생성 system calls» msg_send» msg_receive» msg_rpc (remote procedure call)» port_allocate : 새 mailbox 생성, buffer size = 8, FIFO order» port_status : 주어진 mailbox의메시지수반환 메시지형태» 고정길이 header 메시지길이 두 mailbox 이름 ( 그중하나는 sender 의 mailbox; reply 위한 return address 포함 )» 가변길이 data portion: 정형화된 (typed) 데이터항목들의리스트 3.55
Mach send & receive send 연산» 수신 mailbox 가 full 이아니면메시지복사» 수신 mailbox 가 full 이면 4 가지중선택 1 2 3 4 mailbox 에빈공간이생길때까지대기 최대 n 밀리초대기 기다리지않고즉시복귀 메시지를임시로 cache : 메시지하나만 OS 가보관 ( 메시지가실제로목표 mailbox 에들어갔을때 reply ; only one pending message)» line printer driver 등서버태스크경우 receive 연산» 어떤 mailbox 또는 mailbox set로부터메시지를읽을지를명시» 지정된 mailbox 로부터또는 mailbox set 중한 mailbox 로부터메시지수신» 읽을메시지없으면최대 n 밀리초대기하거나대기하지않음 메시지시스템의단점» double copy(sender mailbox, mailbox receiver)» Mach 는 virtural memory 기법으로두번복사않음 ( 송신스레드와수신스레드를같은주소공간으로 mapping 시킴 ) 3.56
IPC 실례 : Windows XP XP subsystem server 와메시지전달방식으로통신 : 지역프로시주어호출기능 (LPC; Local Procedure Call facility)» LPC: RPC(Remote Procedure Call) 기법과유사 연결포트 (connection port) 와통신포트 (communication port) 사용 통신작업» 클라이언트가연결포트객체에대한 handle 을 open» 클라이언트가연결요청» 서버는두개의사적인 (private) 통신포트를생성하고클라이언트에게두포트중하나의 handle 을돌려줌» 클라이언트와서버는해당통신포트의 handle 을이용하여메시지를보내거나, 응답호출 (callback) 을하거나, 응답 (reply) 을기다림 세가지메시지전달기법» 포트의메시지큐 (~256 bytes) 를중간저장소로이용, 즉시응답하기어려울때알려주는 callback 기법사용가능» 전송할메시지가크면공유메모리인섹션객체 (section object) 를이용, 섹션객체의포인터와크기정보전송하여데이터복사피함, 즉시응답하기어려울때알려주는 callback 기법사용가능» quick LPC : 클라이언트가연결요청후 quick LPC 지시, 서버는클라이언트전용서버스레드 (dedicated server thread) 생성 연결요청, 메시지담을 64KB 섹션객체, 동기화를수행하는한쌍의사건객체 (event pare object) 처리 장점 : 메시지복사, 포트객체사용, 호출한클라이언트파악위한 overhead 제거 단점 : 다른두방법보다많은자원사용 메시지전달 overhead 감소위해여러메시지들을한메시지로 batch 하기도함 3.57
Windows XP 지역프로시저호출 3.58
클라이언트 - 서버통신 (1): 소켓 (Socket) 소켓은종단점 (endpoint) 프로세스간상호양방향통신방식 종단점 = IP 주소와포트번호결합 소켓 117.16.244.59:6666 호스트» 117.16.244.59 포트 6666 통신은한쌍의소켓을포함 네트워크를통한통신가능 소켓을통한프로세스통신은클라이언트 - 서버모델 (client-server model) 활용» 한기계에존재하는파일을다른기계에서프린트» 한기계에서다른기계로파일을전송 3.59
Socket 3.60
Time-of-Day: Server.java import java.net.*; import java.io.*; (Linux) $ Java Server 실행은방화벽꺼야함 public class DateServer # /sbin/service iptables stop 또는 { # /etc/init.d/iptables stop public static void main(string[] args) { try { ServerSocket sock = new ServerSocket(6013); // now listen for connections while (true) { Socket client = sock.accept(); // we have a connection PrintWriter pout = new PrintWriter(client.getOutputStream(), true); // write the Date to the socket pout.println(new java.util.date().tostring()); // close the socket and resume listening for more connections client.close(); catch (IOException ioe) { System.err.println(ioe); 3.61 1.61
Time-of-Day: Client.java import java.net.*; import java.io.*; public class DateClient { public static void main(string[] args) { try { // this could be changed to an IP name or address other than the localhost Socket sock = new Socket("127.0.0.1",6013); InputStream in = sock.getinputstream(); BufferedReader bin = new BufferedReader(new InputStreamReader(in)); String line; while( (line = bin.readline())!= null) System.out.println(line); sock.close(); catch (IOException ioe) { System.err.println(ioe); 3.62 1.62
클라이언트 - 서버통신 (2): 원격프로시저호출 RPC 한호스트의클라이언트프로시주어가원격에있는서버호스트의프로시저를호출할수있게하는가장일반적인클라이언트 / 서버지원기법» 구조화가잘된고수준 (high-level) 메시지전송 (cf.) 소켓통신은저수준패킷스트림전송» Sun 의 NFS (Network File System) 구현에유용하게이용됨» rpcbind ( 전신은 portmapper) 가 port number 111 로서비스 (ref.) /etc/services 의 sunrpc» Sun RPC 가가장많이이용됨 역사» 1981 RPC 기반 Xerox Courier» 1985 Sun RPC package: ONC(Open Network Computing) RPC, XDR(eXternal Data Representation) TCP 또는 UDP 상에서동작하는 socket API 들로구현 공개소스 RPCSRC 1990 초 TLI (Transport Layer Interface): XTI(X/Open Transport Interface) 의전신 공개소스 TI (Transport Independent)-RPC» 1980 중반 : RPC 기반 Apollo NCA(Network Computing Architecture) RPC, NIDL(Network Interface Definition Language)» 1989 DCE(Distributed Computing Environment) RPC 3.63
Execution of RPC (Remote Procedure Call) RPC(Remote procedure call)» 네트워크상의프로세스들사이에서프로시저호출 (procedure calls) 을추상화 클라이언트측스터브 (stub)» 원격서버와포트를찾고» 파라미터를정돈 (marshal) 하여» 메시지전달 서버측스터브 (stub)» 원격서버의프로시저에대한대행자 (proxy) 로서» 메시지받아» 정돈된파라미터를풀어 (unmarshal)» 프로시저를수행함 3.64
Sun RPC 예제 1: DATE_PROG 구성» rpcgen: remote procedure interface(date.x) 를컴파일하여 server stub 와 client stub 를생성» XDR(eXternal Data Representation): 다른시스템간에이식가능한형태로데이터를코드화하는표준방법» run-time library: 모든세세한것들을다룸 ; lnsl(network Service Library) 소스코드» RPC 명세파일 date.x» 서버프로그램 date_proc.c» 클라이언트프로그램 rdate.c 3.65
Sun RPC 예제 1: DATE_PROG 처리방법 % rpcgen date.x % gcc -o date_svc date_proc.c date_svc.c lnsl % gcc -o rdate rdate.c date_clnt.c ln 니 실행방법» 서버호스트에서 $ date_svc & ( Linux 에서는 super user 만서버실행가능 )» 클라이언트호스트에서 $./rdate 호스트이름 ( 도메인이름또는 IP 주소 ) ( 실행파일이 rdate 인경우 /usr/bin/rdate 가이미존재할수있으므로 rdate 명령앞에현재디렉토리./ 붙여서./rdate 로실행시킴 ) time on host = 984459987» 00:00:00 GMT(Greenwitch Mean Time) January 1, 1970 부터의초의수 time on host = Tue Mar 13 14:06:27 2001 실습 ( 반대의경우도실습 )» 서버 (117.16.244.53) 호스트 : $ date_svc &» 클라이언트 (117.16.244.59) 호스트 : $./rdate 117.16.244.53 (cf.) $ which rdate /usr/bin/rdate 3.66
Sun RPC 예제 1: DATE_PROG 3.67
Sun RPC 예제 1: DATE_PROG RPC 명세파일 : date.x program DATE_PROG { version DATE_VERS { long BIN_DATE(void) = 1 ; /* procedure no. = 1 */ string STR_DATE(long) = 2 ; /* procedure no. = 2 */ = 1 ; /* version no. = 1 */ = 0x31234567 ; /* program no. = 0x31234567 */ 프로그램번호» 0x00000000 ~ 0x1fffffff Sun 에의해정의된» 0x10000000 ~ 0x3fffffff 사용자에의해정의된» 0x40000000 ~ 0x5fffffff 일시적인 (transient)» 0x60000000 ~ 0xffffffff 예약된 (reserved) 3.68
Sun RPC 예제 1: DATE_PROG 서버프로그램 : date_proc.c (Unix version) /* date_proc.c */ #include <rpc/rpc.h> #include "date.h" long * bin_date_1() { static long timeval ; long time() ; timeval = time((long *) 0) ; return(&timeval) ; char ** str_date_1(bintime) long *bintime ; { static char *ptr ; char *ctime() ; ptr = ctime(bintime) ; return(&ptr) ; 3.69
Sun RPC 예제 1: DATE_PROG 클라이언트프로그램 : rdate.c (Unix version) #include <stdio.h> #include <rpc/rpc.h> #include "date.h" /* generated by rpcgen */ main(argc, argv) int argc; char *argv[]; { CLIENT *cl; /* RPC handle */ char *server; long *lresult; /* return value from bin_date_1() */ char **sresult; /* return value from str_date_1() */ if (argc!= 2) fprintf(stderr, "usage: %s hostname\n", argv[0]); server = argv[1]; if ((cl = clnt_create(server,date_prog,date_vers,"udp")) /* client handle 생성 */ == NULL) clnt_pcreateerror(server); if ((lresult = bin_date_1(null, cl)) == NULL) clnt_perror(cl, server); printf("time on host %s = %ld\n", server, *lresult); if ((sresult = str_date_1(lresult, cl)) == NULL) clnt_perror(cl, server); printf("time on host %s = %s", server, *sresult); clnt_destroy(cl); 3.70
Sun RPC 예제 1: DATE_PROG 서버프로그램 : date_proc.c (Linux version) /* date_proc.c */ #include <stdio.h> #include <rpc/rpc.h> #include "date.h" #include <time.h> long *bin_date_1_svc(void *arg1, struct svc_req *arg2) { static long timeval; /* must be static */ timeval = time((long *) 0); return(&timeval); char **str_date_1_svc(long *bintime, struct svc_req *arg2) { static char *ptr; /* must be static */ ptr = ctime(bintime); /* convert to local time */ return(&ptr); 3.71
Sun RPC 예제 2: SQUARE_PROG RPC 명세파일 : square.x struct square_in { /* input argument */ long arg1; ; struct square_out { /* output result */ long res1; ; program SQUARE_PROG { version SQUAREPROG { square_out SQUARE_PROC (square_in) = 1; /* procedure no. =1 */ = 1; /* version number */ = 0x31230000 /* program number */ 소스코드 : square.x server.c client.c 처리방법 % rpcgen square.x % gcc -o server server.c square_svc.c square_xdr.c -lnsl % gcc -o client client.c square_clnt.c square_xdr.c lnsl (RPC 명세파일에구조체를포함하기때문에 square_xdr.c 파일이생성되므로컴파일시 square.xdr.c 파일을반드시포함해야함 ) 3.72
Sun RPC 예제 2: SQUARE_PROG 3.73 1.73
Sun RPC 예제 2: SQUARE_PROG 3.74 1.74
Sun RPC 예제 2: SQUARE_PROG 서버프로그램 : server.c (Unix version) #include square.h square_out * squareproc_1 (square_in *inp, struct svc_req *rqstp) { static square_out out ; out.res1 = inp -> arg1 * inp -> arg1 ; return (&out); 3.75
Sun RPC 예제 2: SQUARE_PROG 클라이언트프로그램 : client.c (Unix version) #include square.h int main(int argc, char **argv) { CLIENT *cl ; square_in in ; square_out *outp ; if ( argc!= 3 ) clnt_perror(cl, usage : client <hostname> <interger_value> ); cl = cint_create(argv[1], SQUARE_PROG, SQUARE_VERS, tcp ); in.arg1 = (long)atol(argv[2]); if ( ( outp = squareproc_1(&in, cl) ) == NULL) clnt_perror( cl, argv[1] ) ; printf( result : %ld\n, outp -> res1); exit(0) 3.76
Sun RPC 예제 2: SQUARE_PROG 서버프로그램 : server.c (Linux version) #include "square.h" square_out * squareproc_1_svc(square_in *inp, struct svc_req *rqstp) { static square_out out; out.res1 = inp->arg1 * inp->arg1; return(&out); 3.77
클라이언트 - 서버통신 (3): 원격메소드호출 RMI RPC 의 Java 버전» 저수준 (low-level) 소켓을이용하지않고원격객체의메소드를호출할수있는방법을제공하는객체지향언어인 Java 기반의분산컴퓨팅환경 ( 클라이언트 / 서버지원 ) 을위한미들웨어 (RPC 와유사 )» 스레드 (thread) 가원격객체 (Remote Object) 의메소드 (method) 호출» 다른 Java Virtual Machine 상에있는객체는 원격 객체 RPC 보다좋은점» 객체지향적이다.» 프로그램작성및사용이쉽다.» 안전하고보안성이있다.» 기존시스템과통합해서사용할수있다. 작성절차» 원격인터페이스를정의한다.» 원격인터페이스를구현 (implement) 하는원격객체 ( 서버 ) 를작성한다» 원격객체를이용하는프로그램 ( 클라이언트 ) 을작성한다.» stub 와 skeleton 클래스를생성한다.» rmiregistry 를실행시킨다.» 서버와클라이언트를실행시킨다. 3.78
RMI (Remote Method Invocation) RPC versus RMI» RPC : Procedural Programming Style» RMI : Object-Oriented Programming Style» RPC 의매개변수 : Ordinary Data Structures» RMI 의매개변수 : Objects Stubs and Skeletons» Stub 클라이언트에상주하는원격객체의대리인 (proxy) 매개변수들을 Marshalls ( 메소드이름과인자들의꾸러미생성 ) 해서서버로보냄» Skeleton 서버에상주 매개변수를 Unmarshalls 해서서버에전달함 매개변수» Marshall 된매개변수가 Local (Non-Remote) Objects 이면객체를바이트스트림으로기록해주는객체순서화 (Object Serialization) 기법을이용해서복사에의해 (by Value) 전달» Marshall 된매개변수가 Remote Objects 이면참조에의해 (by Reference) 전달 : RMI 의장점 Remote objects» java.rmi.remote 를확장한 Interface 로선언되어야함 extends java.rmi.remote» 모든메소드는 java.rmi.remoteexception 을발생시켜야함 throws java.rmi.remoteexception 3.79
RMI (Remote Method Invocation) RMI(Remote Method Invocation) 는 RPC 와유사한 Java 기능 RMI 는한컴퓨터의 Java 프로그램이다른컴퓨터의원격객체메소드를호출할수있게함 3.80
매개변수정돈 (Marshalling Parameters) 3.81
RMI 프로그램예제 원격인터페이스구현 MessageQueueImpl.java MessageQueue.java javac server MessageQueueImpl.class MessageQueueImpl_skel.class rmic MessageQueueImpl_stub.class Factory.java Producer.java Consumer.java javac Factory.class client 3.82
RMI 프로그램예제 구성» 원격인터페이스 : MessageQueue.java» 서버프로그램 : MessageQueueImpl.java» 클라이언트프로그램 : Factory.java, Producer.java, Consumer.java 원격서버와클라이언트 Naming 시반드시 ip 와고유한 service 이름명시 ( 서버 ) Naming.rebind("//117.16.244.59/myMessageServer", server); ( 클라이언트 ) Naming.lookup("rmi://117.16.244.53/myMessageServer", server); Policy File : New with Java 2 grant { ; permission java.net.socketpermission "*:1024-65535", "connect,accept"; (Linux) $ Java Server 실행은방화벽꺼야함 # /sbin/service iptables stop 또는 # /etc/init.d/iptables stop 3.83
RMI 프로그램예제 실행순서 1. 모든소스파일컴파일 $ javac MessageQueue.java MessageQueueImpl.java Factory.java Producer.java Consumer.java 2. rmic 로 stub 와 skeleton class 파일생성 $ rmic MessageQueueImpl 3. 레지스트리서비스시작 (rmiregistry) osagent 또는 rpcbind 디몬에해당 $ rmiregistry & (Unix & Linux) 또는 C:\> start rmiregistry (Windows) 4. 원격서버객체의인스턴스생성 (JDK 1.2 이상버전에서는인증해주어야함 ) $ java -Djava.security.policy=java.policy MessageQueueImpl (JDK 1.2 이상 ) 또는 $ java MessgeQueueImpl (JDK 1.1) 5. 클라이언트에서원격객체실행시작 $ java -Djava.security.policy=java.policy Factory (JDK.2 이상 ) 또는 $ java Factory (JDK 1.1) 3.84
3 장정리 PCB & task_struct 프로세스생성과종료» fork» fork + exec 유한버퍼생산자 - 소비자 (bounded-buffer producer-consumer) 문제» Version 1: 공유메모리를이용한해결책 (3.4.1 절 )» Version 2: 메시지전달 (IPC) 을이용한해결책 (3.4.2 절 ) 클라이언트 - 서버통신» Socket» RPC» RMI 3.85