Exception Control Flow Review & 실습

28
Exception Control Flow Review & 실실 2011. 11.23 실 실 실 A 실 실실실실실 실실실실실실실 .! 실실 , 실실실실 실실실실 , thread 실실 실 실실실실 실실실실실 실실실 실 실실실 실실실 . ! ppt 실 실실실실 실실 실실실 실 실실실 실 Q&A 실실실실 실실실실실 . ^

description

Exception Control Flow Review & 실습. A 반 질문리스트 반영되었습니다 .! 만 약 , 해결되지 않았다면 , thread 수업 전 방문하여 질문하시고 이해할 수 있도록 합니다 . ! ppt 에 추가하지 못한 질문은 맨 마지막 장 Q&A 리스트에 넣었스니다 . ^. 2011. 11.23 최 윤 정. 들어가기 전에 .. 동기와 비동기의 의미를 실행으로 알아봅니다. 그동안의 C code 는 1. 위에서 아래로 흘러내려오는 흐름 . 즉 , flow 가 있었습니다 . - PowerPoint PPT Presentation

Transcript of Exception Control Flow Review & 실습

Page 1: Exception Control Flow Review &  실습

Exception Control FlowReview & 실습

2011. 11.23

최 윤 정

A 반 질문리스트 반영되었습니다 .!

만약 , 해결되지 않았다면 ,

thread 수업 전 방문하여 질문하시고 이해할 수 있도록 합니다 . !

ppt 에 추가하지 못한 질문은 맨 마지막 장 Q&A 리스트에 넣었스니다 . ^

Page 2: Exception Control Flow Review &  실습

2

들어가기 전에 ..동기와 비동기의 의미를 실행으로 알아봅니다 .

그동안의 C code 는 1. 위에서 아래로 흘러내려오는 흐름 . 즉 , flow 가 있었습니다 .

폭포처럼 한번 떨어져 내려온 이상 for(),while(), goto 등 jump 하는 기능이 없으면 다시는 위로 올라갈 수 없는 구조였습니다 .

2. 게다가 동기적인 흐름을 따랐습니다 .

printf(“ 데이터를 입력하세요 : ”);

scanf(“%d”, &data);

printf(“ 입력을 받기 전까지 이후 구문은 출력되지 않습니다 .\n”);

printf(“ ######\n”);

그러나 , system call 은 , fork() 나 signal() 은 달랐습니다 . 동기 / 비동기적으로 수행됩니다 .

동기적 : wait(), sleep(), pause(), fopen().. 등

비동기적 : signal() // 시그널 받을 때까지 기다리지 않아요 .

다음의 코드를 다운받아 Visual C++ 에서 수행해보도록 하세요 .

http://home.konkuk.ac.kr/~cris/Class/2011/sp/fork-code/block.exe

방향키를 눌러서 bar 를 움직여 보세요 .

Page 3: Exception Control Flow Review &  실습

3

source : http://home.konkuk.ac.kr/~cris/Class/2011/sp/fork-code/block.zip

이 소스의 동작은 별을 출력하면서도 Bar 를 욺직이고 있어요 .Bar 을 욺직이기 위해 방향 key 를 입력하는 동안별을 출력하는 부분이 멈추어 있지 않습니다 .만약 키를 입력받고자 scanf(); 나 getchar() 를 썼다면 ?입력받기전 출력부분도 ‘대기’합니다 . Why?!

while 루프 내부를 보면 ,GetAsyncKetState() 라는 함수가 쓰여져 있어요 .비동기식으로 키를 입력받아라 . 하는 함수죠 .(Khbit() 과 마찬가지 )해당 키가 눌려졌는지 아닌지를 catch 하여 눌려졌다면 동작합니다 . 동작상으로는 system call 에서 signal 과 유사한 부분이 있죠 ?

과제를 통해 조사해 보았겠지만 , 실행예를 통해 확인해 보세요 .

while(1){

…( 중략 )

if( GetAsyncKeyState(LEFT) ) bar_x--;else if(GetAsyncKeyState(RIGHT)) bar_x++;else if(GetAsyncKeyState(ESCAPE)) {

system("cls"); gotoxy(25,10);system(" 종료합니다 ."); break;

}….

}return 0;

Page 4: Exception Control Flow Review &  실습

4

실습 전 알아두어야 할 것 process 에 대한 이해

프로세스 상태 : Ready , Running, Waiting, Terminated

ps 명령어로 status 보기 (#man ps 로 확인하세요 )

fork() – exec 계열함수 () 의 동작

부모 - 자식프로세스

자식은 .. 기본적으로 부모가 관리해야 한다 . (Reaping.)

만약 , 외부에서 부모프로세스만 kill -9 하면 부모만 종료 . 자식은 부모를 잃었으므로 ppid 도 함께 잃음 . ( 후 ppid = 1)

따라서 강제종료 시에는 가장 하위자식부터 kill -9. ( 이제 하지 마세요 ^^)

부모는 자식을 작업 종료시 까지 기다려주고 , 자식프로세스는 부모프로세스에게 종료 요청을 해주자 .

자식은 낳는 것보다 잘 키우는 것이 더 어렵고도 중요합니다 . 자식이 어떻게 자라는지 (status) 죽음에 대해서도 관심을 가져야 해요 .

SIGNAL 을 이용하여 process 에 신호 (message) 를 보낼 수 있습니다 .

( 리눅스 : /usr/include/bits/signum.h 에 signal macro 정의 )

process 가 죽는 경우는 다양합니다 . 예 ) Kill -9 pid //kill –SIGKILL pid( 강제종료 ) vs. Kill -SIGTERM pid // terminated

System call

일반 C- 라이브러리 함수와 system call 함수는 다릅니다 .! fork(), execl(), wait(), signal( ) 등 ..

fork 함수 호출을 통한 프로세스 생성

Page 5: Exception Control Flow Review &  실습

5

ps : process status Option :

-a : 모든 프로세스 상태 출력 -e : 현재 실행중인 모든 프로세서 상태 출력 -f : 프로세스 상태 full list 로 출력 -l : 프로세스 상태 long list 로 출력 -m : 메모리 정보를 출력 -t TTY : 지정한 TTY 를 가진 프로세스 정보 출력 -u : 사용자 이름 , 시작시간을 보여준다 -p PID : 지정한 PID 를 가진 프로세스 정보 출력 -u UID : 지정한 UID 를 가진 프로세스 정보 출력 -g GID : 지정한 GID 를 가진 프로세스 정보 출력

프로세스 상태보기 PID(Process ID) : 프로세스마다 주어지는 번호 TTY(Tele TYpewrite) : 명령어가 실행되는 터미널의 번호 STAT(STATe) : 실행되고 있는 프로세스 상태 R : 실행 중 혹은 실행될 수 있는 상태 S : sleep I : idle ( 비활동 상태 : BSD / 중간적 상태 : sysV) T : 정지된 상태 (suspend) Z : 좀비 (zombie) 프로세스 D : 디스크 관련 대기 상태 (BSD) P : 페이지 관련 대기 상태 (BSD) X : 메모리 확보를 위해 대기 중 (sys V) K : 사용 가능한 커널 프로세스 (aix) W : 스왑 out 된 상태 N : nice 되어진 상태 > : 우선 순위가 인위적으로 높아진 상태

START(START) : 프로세스가 시작된 시간TIME(TIME) : CPU 가 사용한 시간USER(USER) : 사용자의 이름COMMAND(COMMAND) : 사용자가 실행한 명령어UID(User ID) : 사용자의 ID

(Parent Group ID) : 사용자 부모 프로세스의 그룹 ID

SID(Session ID) : 세션 ID

PRI(PRIority) : 실행하는 우선 순위에 따른 프로세스NI(Nice) : nice 에 의한 우선 순위에 따른 프로세스RSS(Resident Set Size) : 프로세스가 사용하는 메모리의 크기SZ(SiZe) : 프로세스가 사용하는 자료와 스택의 크기SHRD(ShaReD) : 프로세스가 사용하는 공유 메모리%CPU : 프로세스가 사용하는 CPU 점유율%MEM : 프로세스가 사용하고 있는 메모리 점유율WCHAN : 프로세스가 실행하고 있는 커널 루틴

Page 6: Exception Control Flow Review &  실습

6

kill : 현재 수행중인 프로세서에게 시그널을 보낸다 # kill [ -signal ID ] PID // 보통 kill 명령은 프로세서를 죽이는 데에 사용된다 .

# kill –L // 시그널 종류 나열 , /usr/include/bits/signum.h 에 정의됨 시그널의 종류를 지정하지 않으면 프로세서를 종료시키는 의미로 디폴트 시그널 ID 15 번을 보내게 된다 .

1. SIGHUP(HUP) : 연결 끊기 . 프로세스의 설정파일을 다시 읽는데 사용된다 . 2. SIGINT(INT) : 인터럽트 3. SIGQUIOT(QUIT) : 종료 4. SIGILL(ILL) : 잘못된 명령 5. SIGTRAP(TRAP) : 6. SIGIOT(IOT) : IOT 명령 7. SIGBUS(BUS) : 버스 에러 8. SIGFPE(FPE) : 고정 소수점 예외 9. SIGKILL(KILL) : 죽이기 . 이 시그널은 잡히지 않는다 . 10. SIGUSR1(USR1) : 사용자 정의 시그널 1 11. SIGSEGV(SEGV) : 세그멘테이션 위반 12. SIGUSR2(USR2) : 사용자 정의 시그널 2 13. SIGPIPE(PIPE) : 읽을 것이 없는 파이프에 대한 시그널 14. SIGALRM(ALRM) : 경고 클럭 15. SIGTERM(TERM) : 소프트웨어 종료 시그널 , 일반적으로 kill 시그널이 전송되기 전에 전송된다 . 16. SIGKFLT : 코프로세서 스택 실패 17. SIGCHLD(CHLD) : 자식 프로세스의 상태변화 18. SIGCONT(CONT) : STOP 시그널 이후 계속 진행할 때 사용 19. SIGSTOP(STOP) : 정지 . 이 시그널 역시 잡을 수 없다 . 20. SIGTSTP(TSTP) : 키보드에 의해 발생하는 시그널로 Ctrl+Z 로 생성된다 .

Page 7: Exception Control Flow Review &  실습

7

kill 시스템 콜 : Sending Signals

void fork12(){ pid_t pid[N]; int i, child_status; for (i = 0; i < N; i++)

if ((pid[i] = fork()) == 0) while(1); /* Child infinite loop */

/* Parent terminates the child processes */ for (i = 0; i < N; i++) {

printf("Killing process %d\n", pid[i]);kill(pid[i], SIGINT);

}

/* Parent reaps terminated children */ for (i = 0; i < N; i++) {

pid_t wpid = wait(&child_status);if (WIFEXITED(child_status)) printf("Child %d terminated with exit status %d\n",

wpid, WEXITSTATUS(child_status));else printf("Child %d terminated abnormally\n", wpid);

}}

Page 8: Exception Control Flow Review &  실습

8

Zombie 만들기 :// 부모는 종료했으나 , 죽지 않는 child, 이 child 는 어떻게 될가요 ?

void fork8(){ if (fork() == 0) { /* Child */ printf("Running Child, PID = %d\n",getpid()); while (1) ; /* Infinite loop */ } else { printf("Terminating Parent, PID = %d\n",getpid()); exit(0); }}

// 부모는 종료되기 전 , 종료하는 child - zombie 가 되죠 . void fork7(){ if (fork() == 0) {

/* Child */ printf("Terminating Child, PID = %d\n", getpid()); exit(0); } else { printf("Running Parent, PID = %d\n", getpid()); while(1)

//do something ; /* Infinite loop */ }}

부모보다 먼저 ( 아무 말없이 ) 종료되어 status 가 전달되지 않아서 , 자식 프로세스를 reaping 하지 못하는 경우 발생 . - 자식 process 를 기다려주거나 SIGNAL 을 이용하여 처리한다 . !

자식 프로세스는 종료되면서 성공적인 종료를 알리기 위해 0 값을 커널에 리턴합니다 .

그러나 , 이 때 , 커널은 자식 프로세스를 바로 종료시키지 않고 , 부모 프로세스에게 자식이 죽으며 전해준 값 (0) 이 전달될 때까지 기다려줘요 .

자식의 상태정보 값은 부모 프로세스가 커널에게 요청할 때에만 전달됩니다 .

부모가 요청없이 종료했으므로 자식의 신호는 부모에게 전달될 수 없고 , 이 때 자식은 작업은 종료했으나 메모리는 남아있는 zombie 상태가 됩니다 .

Page 9: Exception Control Flow Review &  실습

9

앞 페이지의 두 예제 소스를 보면

부모와 자식간 오고 가는 대화가 없어도 너무 없어요 .

자식이 무엇을 하는지 말든지에 관심없이 자기일 끝났다고 그냥 종료하는 부모와 ..

-> 자식은 ppid() 부모를 잃고 떠돌다가 init 의 자식으로 들어가죠

부모가 있는 자식이되 일련의 허락없이 ( 제멋대로 ) 종료해버리는 자식이 있죠 .

무릇 , 참된 부모는 ..

자식이 어떤 상황에 놓여있는지 파악해야 하며

자식을 기다릴 줄 알아야 하고

무릇 , 자식이라면

자신의 현재 상황을 부모에게 알려주어야 하겠습니다 .

부모에게는 기다림을 권고하고 자식의 학교생활이 궁금할 때 선생님의 도움을 받아자식 프로세스의 상황을 알아볼 수 있듯이

시스템의 도움을 받습니다 . system call

( C 라이브러리 함수가 아니에요 !)

wait() 와 signal()

Page 10: Exception Control Flow Review &  실습

10

wait() 시스템 콜

* fork 를 사용하여 child process 를 생성하는 경우 parent process 는 child process 를 wait 하여 child process 가 zombie 가 되는 것을 막아야 한다 . 자식 프로세스가 종료되면 , 리눅스 커널은 그것의 메모리를 해제하고 파일을 닫는다 . 종료상태는 프로세스의

프로세스 테이블에 저장된다 .

but, 부모프로세스가 자식프로세스의 종료에 대한 관심없이 계속 동작을 수행하는 동안 하나 이상의 이유로 자식프로세스가 종료됐을 때 , 부모프로세스가 이 정보를 가져갈 때까지의 상태에 있는 자식프로세스를 좀비라고 한다 . (Reaping 되지 않은 )

일반적으로는 SIGCHLD 처리 함수안에서 wait, waitpid 함수를 사용하여 child process

가 zombie 가 되는 것을 막는다 .

wait(), waitpid() : process 의 종료나 signal 함수호출신호를 기다리는 경우 호출한 영역에서 일시중지

pause() : signal 을 기다리는 경우

모르는 명령어가 있다면무작정 모른다 . 버티지 말고# man 2 wait 를 실행해보도록 .!

Page 11: Exception Control Flow Review &  실습

11

#man 사용법 보는 방법 # man man : man 명령어에 대한 manual.

The table below shows the section numbers of the manual followed by the types of pages they contain.

1 Executable programs or shell commands 2 System calls (functions provided by the kernel) 3 Library calls (functions within program libraries) 4 Special files (usually found in /dev) 5 File formats and conventions eg /etc/passwd 6 Games 7 Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7) 8 System administration commands (usually only for root) 9 Kernel routines [Non standard]

따라서 쉘명령어 wait 에 대한 manual # man 1 wait

시스템 콜 wait 에 대한 manual # man 2 wait

Page 12: Exception Control Flow Review &  실습

12

wait(), waitpid() 함수를 통해 알 수 있는 child 정보 ( 앞으로는 헤매지만 말고 스스로 찾아보세요… .!!!!!!!!!!)

(#man 2 wait 중 .)

wait 함수 : 자식이 종료될 때까지 , 또는 현재 프로세스를 종료시키거나 시그널 처리 함수를 호출하는 행동을 하는 신호가 전달될 때까지 현재 프로세 스의 실행을 일시 중지시킨다 . 만일 자식이 호출 시간에 이미 종료되었다면 ( 좀비 프로세스 ), 함수는 즉시 리턴한다 . 자식이 사용한 시스템 자원들은 모두 풀어진다 .

waitpid 함수 : pid 인자가 가리키는 자식이 종료될 때 까지 , 또는 현재 프로세스를 종료시키거나 시그널 처리 함수를 호출하는 행동을 하는 신호가 전달될 때까지 현재 프로세스의 실행을 일시 중지시킨다 . 만일 pid 로 지정된 자식이 호출 시간에 이미 종료되었다면 ( 좀비 프로세스 ), 함수는 즉시 리턴한다 .

status, 와 option ( 뒷장 )

pid_t wait(int *status)pid_t waitpid(pid_t pid, int *status, int options);

상태정보를 담아오기 위한 그릇 . 주소 ! 를 보내야 겠죠 ?

Page 13: Exception Control Flow Review &  실습

13

… ( 이어서 )

리턴되는 pid 값은 다음 중 하나이다 . < -1 : 프로세스 그룹 ID 가 pid 의 절대 값과 같은 어떤 자식 프로세스를 기다리라는 의미이다 . -1 : 어떤 자식 프로세스를 기다리라는 의미이다 ; 이것은 wait 에서 나타난 것과 같은 행동을 한다 . 0 : 프로세스 그룹 ID 가 호출 프로세스의 ID 와 같은 어떤 자식 프로세스를 기다리라는 의미이다 . > 0 : 프로세스 ID 가 pid 의 값과 같은 자식을 기다리라는 의미이다 .

options 의 값은 0 이거나 다음 상수의 어떤 것과 OR 이다 .

WNOHANG : 이것은 어떤 자식도 종료되지 않았다면 즉시 리턴하라는 의미이다 .

WUNTRACED : 이것은 멈추거나 상태가 보고되지 않은 자식들을 위해 역시 리턴하라는 의미이다 . 만일 status 가 NULL 이 아니라면 wait 또는 waitpid 는 status 가 가리키는 위치에 상태 정보를 저장한다 . 이 상태는 다음 매크로들로 평가된다 .( 이들 매크로는 인자로써 stat 버퍼 (int 값 !) 를 가지고 있다 . -- 버퍼에 대한 포인터가 아니다 !)

WIFEXITED(status) : 자식이 정상적으로 종료되었다면 non-zero 이다 .

WEXITSTATUS(status) : exit() 를 호출하기 위한 인자나 주 프로그램에서 return 문장을 위한 인자로써 설정되고 종료된 자식의 반환 코드의 최하위 8 비트를 평가한다 . 이 매크로는 WIFEXITED 가 non-zero 를 반환할 때만 평가된다 .

WIFSIGNALED(status) : 만일 자식 프로세스가 잡혀지지 않은 신호때문에 종료되었다면 참을 반환한다 .

WTERMSIG(status) : 자식 프로세스를 종료하도록 야기한 신호의 숫자를 반환한다 . 이 매크로는 만일 WIFSIGNALED 가 non-zero 를 반환할 경우만 평가된다 .

WIFSTOPPED(status) : 반환의 원인이 된 자식 프로세스가 현재 정지되어 있다면 참을 반환한다 .; 이것은 이 함수가 WUNTRACED 를 사용했을 때만 가능하다 .

WSTOPSIG(status) : 자식을 정지하도록 야기한 신호의 숫자를 반환한다 . 이 매크로는 WIFSTOPPED 가 non-zero 를 반환할 경우만 평가된다 .

pid_t wait(int *status)pid_t waitpid(pid_t pid, int *status, int options);

Page 14: Exception Control Flow Review &  실습

14

이제 wait( ) 를 적용해 봅시다 . (1) : int wait(int *child_status).

// 부모는 종료했으나 , 죽지 않는 child, 이 child 는 어떻게 될가요 ?

void fork8(){ int i = 0; if (fork() == 0) {

/* Child */printf("Running Child, PID = %d\n",getpid());while (i < 20) printf(“I want to play~!”);

} else {printf("Terminating Parent, PID = %d\n", getpid());exit(0);

}}

// 자식이 종료되기를 기다렸다가 부모도 종료합니다 .

void fork8-1(){ int status; if (fork() == 0) {

/* Child */printf("Running Child, PID = %d\n",getpid());while (i < 20) printf(“[%d] : I want to play~! \n”, i);

} else {printf(“Good Parent, PID = %d\n", getpid());

wait(&status);printf(“Terminating.! \n”);exit(0); // 이 라인이 없어도 종료는 됩니다 .

}}

무한루프를 마냥 기다릴 수는 없으므로 변경

여기서 , 자식이 종료되기를 wait.!

Page 15: Exception Control Flow Review &  실습

15

이제 wait( ) 를 적용해 봅시다 . (2) : int wait(int *child_status).

#define N 5int main(){ pid_t pid[N]; // 여러 개의 자식을 만들어 pid 를 저장하기 위한 배열 . int i, child_status;

for (i = 0; i < N; i++){ if ((pid[i] = fork()) == 0){ sleep(1); printf("child : %d \n", getpid()); exit(100+i); /* Child 가 종료되면서 100+i 를 들고 갑니다 . } else printf("parent[%d]:%d \n", i, getpid()); }

for (i = 0; i < N; i++) { wpid = wait(&child_status); if (WIFEXITED(child_status)) printf("Child %d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status)); else printf("Child %d terminate abnormally\n", wpid); }}

parent[0]:11136parent[1]:11136parent[2]:11136parent[3]:11136parent[4]:11136child : 11137child : 11139child : 11141Child 11137 terminated with exit status 100Child 11139 terminated with exit status 102Child 11141 terminated with exit status 104child : 11138Child 11138 terminated with exit status 101child : 11140Child 11140 terminated with exit status 103

Page 16: Exception Control Flow Review &  실습

16

wait() 로는 부족한 일

언제 자식 프로세스가 종료될 것인지를 커널이 예측할 수 있을가 ?

무작정 기다리말고 , 자식 프로세스가 종료되는 순간에

커널이 부모 프로세스에게 자식 프로세스가 종료됨을 알려주도록 하자 !

시그널 핸들링 개념의 동기 : code 에 여러 시그널 핸들러를 설치하여 테스트해 봅니다 .

시그널이 발생했을 때 , 미리 준비해 놓은 함수가 호출되도록 연결해주는 작업

signal 함수 / sigaction 함수를 통한 핸들링

(sigaction 함수가 시스템 입장에서는 보다 안정적 .)

Page 17: Exception Control Flow Review &  실습

17

이제 Signal 을 받아 처리해봅시다 .SIGNAL 과 Handler 의 간단한 예 : #include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <sys/wait.h>#include <sys/stat.h>#include <signal.h>

void handler1(int sig){

printf(” process(%d) 에 signal[%d] 이 전달됨 \n”, getpid(), sig);// exit(0); 이 부분을 주석처리 할 때와 하지 않을 때의 차이를 알 수 있겠지요 ?

}

int main(){

pid_t pid, ppid;

signal(SIGINT, handler1); //SIGINT 가 들어오면 handler 를 호출signal(SIGCHLD, handler1); //SIGCHLD 가 들어오면 handler 를 호출 , handler2 를 만들어 호출할 수도 있겠죠 ?

// …..

if (fork() == 0) {

printf("Running Child, PID = %d\n", getpid());

while(1) ; // 무한루프} else {

printf("Running Parent, PID = %d\n", getpid());

while(1) ; // 무한루프 }

}

// 부모와 자식 둘 다 무한 루프 상태 , wait() 는 적합하지 않아요 . Why?!

// signal 을 이용하여 어떤 처리를 할 수 있을까 .

// 일단 , 백그라운드 동작 상태 , 혹은 다른 쉘에서 SIGNAL 을 보내주어야 합니다 .

// 1. kill -9 를 이용하여 각각의 프로세스를 강제종료가 가능하다 . 단 자식먼저 .

// 2. SIGNAL handler 를 설치하여 처리한다 .

// 또는 , 소스 내부에서 kill() 함수를 통해 SIGNAL 을 전달해야 합니다 .(slide 18,

22)

Page 18: Exception Control Flow Review &  실습

18

이제 wait() 와 SIGNAL()을 적용해 봅시다 .

#include <unistd.h>#include <string.h>#include <stdio.h>#include <sys/types.h>#include <sys/wait.h>#include <signal.h>

void zombie_handler(){ int status; int spid;

spid = wait(&status);

printf(" 자식프로세스 wait 성공 \n");

printf("========================\n");

printf("PID : %d\n", spid);

printf("Exit Value : %d\n", WEXITSTATUS(status));

printf("Exit Stat : %d\n", WIFEXITED(status));}

int main(){ int pid; int status; int spid; int i;

// SIGCHLD 에 대해서 시그널핸들러를 설치한다 . signal(SIGCHLD, zombie_handler);

for (i = 0; i < 3; i++) { pid = fork(); int random_value = (random()%5)+3; if (pid == 0) { // 랜덤 값을 이용하여 기다린 후 종료한다 . printf("I will be back %d %d\n", random_value, getpid()); sleep(random_value); return random_value; } } // ( 동기함수 ) 키보드 대기 , ( 모든 자식이 죽을 때 즈음 키 입력 ) getchar(); // 너무 빨리 치면 어떤 상황이 올까요 ?

printf(" 종료합니다 .\n\n");}

Page 19: Exception Control Flow Review &  실습

19

wait(&status) 만으로도 상태정보를 읽어와 해석할 수 있는데

waitpid() 는 왜 사용할까요 ?

자식이 여러 개인 경우라면 wait() 로는 곤란하겠죠 ?

이미 종료했는데 마냥 임의의 자식을 wait() 하라고 하면 이제 blocking

상태에 이릅니다 .

waitpid() 의 적용예는 여러분이 조사해보도록 하세요 .

( 중간 / 기말에 반영하도록 하겠습니다 .)

Page 20: Exception Control Flow Review &  실습

20

이제 다양한 SIGNAL 을 보내봅니다 . SIGSEGV 유발하는 scanf.c

void handler(int sig){ printf(” process(%d) 에 signal[%d] 이 전달됨 \n”, getpid(), sig); exit(0);}int main() { int i=0; int a[5]={0}; char str[5]; printf("scanf 명령 중 SIGSEGV, SIGABRT \n");

signal(SIGSEGV, handler); signal(SIGABRT, handler); while(1) { scanf("%s", str); printf("str = %s \n", str); a[i] = i; printf("a[%d] = %d \n", i, i); i++; }}

[root@localhost test]# ./scanfscanf 명령 중 SIGSEGV, SIGABRT1346798abcdefgad;kja;dksfja;kdsfadsfsdafadsfsdfadsfasdfasdfstr = %Error : Segmentation Fault !!

[root@localhost test]# ^C

Page 21: Exception Control Flow Review &  실습

21

Kill() 를 통해 Signal 을 보내봅니다 . void int_handler(int sig) {

printf("Process %d received signal %d\n", getpid(), sig);

exit(0);

}

void fork13() {

pid_t pid[N];

int i, child_status;

signal(SIGINT, int_handler);

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

if ((pid[i] = fork()) == 0) while(1) ; /* child infinite loop

}

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

printf("Killing process %d\n", pid[i]);

kill(pid[i], SIGINT);

}

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

pid_t wpid = wait(&child_status);

if (WIFEXITED(child_status)) printf("Child %d terminated with exit status %d\n", ,

WEXITSTATUS(child_status));

else printf("Child %d terminated abnormally\n", wpid);

}

}

# ./forksKilling process 25417Killing process 25418Killing process 25419Killing process 25420Killing process 25421Process 25417 received signal 2Process 25418 received signal 2Process 25420 received signal 2Process 25421 received signal 2Process 25419 received signal 2Child 25417 terminated with exit status 0Child 25418 terminated with exit status 0Child 25420 terminated with exit status 0Child 25419 terminated with exit status 0Child 25421 terminated with exit status 0#

Page 22: Exception Control Flow Review &  실습

22

Internal Signal 의 예 : Alarm ( 동기식 signal)/* * internal.c - A program that responds to interally generated events (SIGALARM signals) */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>

int beeps = 0;

/* SIGALRM handler */void handler(int sig) {

printf("BEEP\n"); fflush(stdout);

if (++beeps < 10) beeps < 2 로 바꾸면 ?

alarm(2); //2초마다 SIGALRM 전송 else {

printf("BOOM!\n");

exit(0);

}

}

int main() {

printf(" alarm(0) 일 때 종료 "); signal(SIGALRM, handler); alarm(2); /* send SIGALRM in 2 second */

while (1) { sleep(1); printf(". Beeps : %d \n“,beeps);

if(beeps > 3) alarm(0); // /* handler returns here */ }}

Page 23: Exception Control Flow Review &  실습

23

External Signal : ( 비동기식 signal)/* * external.c - A program that responds to externally * generated events (ctrl-c) */#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <signal.h>

void handler(int sig) { printf("You think hitting ctrl-c will stop the bomb?\n"); sleep(2); printf("Well..."); fflush(stdout); printf("OK\n"); // exit(0); 여러 번의 시그널을 받아보기 위해서 주석처리하고 수행해 보세요 .}

int main() {

printf(" backround 수행후 ctrl+c 또는 kill -SIGINT pid 로 SIGINT 를 전송 \n"); signal(SIGINT, handler); /* installs ctl-c handler */ while(1) { }}

[root@localhost test]# ./external &[root@localhost test]# ps PID TTY TIME CMD10907 pts/12 00:00:00 bash11217 pts/12 00:00:03 external11223 pts/12 00:00:00 ps[root@localhost test]# kill -2 11217[root@localhost test]# You think hitting ctrl-c will stop the bomb?kill -2 11217Well...OK [root@localhost test]# kill -2 11217[root@localhost test]# You think hitting ctrl-c will stop the bomb?Well...OK[root@localhost test]# fg./external^CYou think hitting ctrl-c will stop the bomb?^CWell...OKYou think hitting ctrl-c will stop the bomb?^CWell...OKYou think hitting ctrl-c will stop the bomb?Well...

Page 24: Exception Control Flow Review &  실습

24

시스템 콜 함수에 대해서는 더 조사해 보세요 http://

www.joinc.co.kr/modules/moniwiki/wiki.php/Site/Assembly/Documents/article_linux_s

ystemcall_quick_reference

파일 및 파이프 open(), read(), write(), close() …

seek(), fstat(); ..

popen() //process 의 stdout 을 파일로 받는다 .

chmod(), chown();

pipe() …

Proccess 제어 fork(), getpid(), kill(), signal(), semaphore() 등

기타 공유메모리 관련 : shmget()

시스템 시간 : time()

(Non-Logical Jump 는 skip 합니다 .) 수고했습니다 .!!!

Page 25: Exception Control Flow Review &  실습

25

SIGNAL 읽어보기 :

기본 1 : 시그널 처리기 http://

www.joinc.co.kr/modules/moniwiki/wiki.php/Site/system_programing/Signal/SignalHow

기본 2 : 시그널 처리기 http://

www.joinc.co.kr/modules/moniwiki/wiki.php/Site/system_programing/Signal/SignalHow2

sigaction : 좀더 잘 처리하기 http://

www.joinc.co.kr/modules/moniwiki/wiki.php/man/2/sigaction?cx=002661009167463862046%3A8oq6cxlfibu&cof=FORID%3A9&q=sigaction&sa=Search&ie=EUC-KR#1257

Page 26: Exception Control Flow Review &  실습

26

A,B 반 Q&A

Q1) 기본이해는 쉬운데 시험문제가 과제 , 응용이 어렵습니다A) 매무 평이한 질문이면서 또 , 매우 심각한 질문이기도 합니다 .

진정 ‘기본’을 이해할 수 있었다면 이제 다음으로 진행할 수 있어야 합니다 . 예를 들어 ‘숫자’를 알고 ‘더하기’의 의미를 이해했다면 , 그리고

1+2, 3+4, 5+6 을 연습했다면 8+9 도 , 21+34 에 대해서도 계산할 수 있어야 합니다 .

다음으로 진행하기가 힘들다면 .., 지금 내가 ‘기본’을 이해하고 있는 것이 사실인가 ? 이해했다고 믿는 것은 아닌가 ? 에 대해 한번쯤 의문을 가져야 하겠습니다 . 그 후 , 다시 개념의 추상화 구체화 하여 이해하려는 시도가 있어야 하겠습니다 .

Page 27: Exception Control Flow Review &  실습

27

Q2) 부모프로세스가 죽을 때 자식프로세스가 같이 죽는게 맞나요 ?

A) 일반적으로는 , 부모가 정상종료 / 비정상종료 할 때 , 멀쩡히 살아있는 자식을 데려가 함께 죽여버리지는 않습니다 . Reaping. 즉 자식이 사용하던 자원을 거두어주는 역할을 해야하므로 먼저 죽는 일은 없도록 해야 합니다 .!

( 일부러 죽는 경우는 있습니다만 , 그전에 어떠한 처리가 필요한 거죠 )

그래서 부모는 자식이 살아있는 한 죽지않도록 waiting 을 해주어야 하고

자식이 최소한 죽었는지 살았는지의 signal 을 요청하여 catch 해야 합니다 .

슬라이드 앞장부터 큰 제목을 위주고 다시 읽어본 후 , 소스를 분석해보도록

하세요 .

Page 28: Exception Control Flow Review &  실습

28

Q3) fork() 는 어떤 프로그램 만들 때 자주 쓰이나요 ?

A) 흔히 .. 할 일은 많은데 시간은 제한되어있고 몸은 하나밖에 없어서 아쉬울 때가 많습니다 . 몸이 하나만 더 있었다면 작업에 대한 역할을 분담할 수 있을 겁니다 . 크게 말하면 fork() 는 작업의 역할을 분담할 수 있도록 별도의 process 를 생성하는 거죠 . ( 반면 , Thread 는 한 프로세스 내에서의 작업을 분담하여 같이 한다는 의미가 더 큽니다 .)

흔히 요즘의 프로그램들은 ‘다중 xx 시스템’ ‘멀티 xx 시스템’이라는 타이틀이 많이 붙어요 .

연습문제 수준을 벗어나면 , 무조건 돌아가게만 만드는 프로그램이 아니라 , 복잡한 작업 네트웍상에서 여러 개의 프로그램이 서로 잘 동작하도록 하려면 새로운 일꾼도 필요합니다 . 시스템 서버와 협력하여 일련의 signal 도 송수신 해주어야 할 것입니다 . 내년에 많이 쓰게 되겠죠 ? ^^

Q4) fork(),sigaction() 등의 함수에 대한 사용법을 모르겠습니다 . 인자와 예제설명이 필요합니다 .

B) 음…요런 내용은 .. 사탕 줄 테니까 개별 방문 하세요 .!!