프로세스의 개요
프로세스?
-> 현재 실행중인 프로그램.
-> 입력이 들어가고 나서 출력이 나오기 까지 수행되는 동안.
프로세스 구조
표준 출력 장치 변경
- who > who.txt
multihp1:/data2/jsp/jsp09>ll -R > 20081226
multihp1:/data2/jsp/jsp09>touch xxxx
multihp1:/data2/jsp/jsp09>touch yyyy
multihp1:/data2/jsp/jsp09>touch zzzz
multihp1:/data2/jsp/jsp09>touch xyz
multihp1:/data2/jsp/jsp09>ll -R > 20081227
multihp1:/data2/jsp/jsp09>diff 20081226 20081227
2>
- 표준 에러 출력 장치 변경
- 이름은 파일을 써도 되고 장치 명을 써도 됨.
- multihp1:/data2/jsp/jsp09>ls passwd1 apsswd9
apsswd9 not found
passwd1
multihp1:/data2/jsp/jsp09>ls passwd1 passwd9 2> ls.out
passwd1
multihp1:/data2/jsp/jsp09>cat ls.out
passwd9 not found
- ls passwd1 passwd9 > ls.out 2>&1
- 위와 같은 방법을 재지정(Redirection)
multihp1:/data2/jsp/jsp09>cat ls.out
passwd9 not found
passwd1
Fri Dec 26 09:17:07 KST 2008
multihp1:/data2/jsp/jsp09>date >> ls.out
multihp1:/data2/jsp/jsp09>date > ls.out
multihp1:/data2/jsp/jsp09>cat ls.out
Fri Dec 26 09:19:53 KST 2008
multihp1:/data2/jsp/jsp09>
|
- 파이프(pipe)
- 프로세스 구조와 밀접한 구조.
- 명령과 명령의 사이에 사용.
ls | more
- 와 같이 사용할 경우 ls, more의 프로세스가 둘다 올라감.
- 그리고 파이프가 표준 출력 즉, 파일 1번과 파이프가 연결되고 뒷 프로세스의 파일 0번 과 파이프로 연결된다.
|tee
- 티!!!!!
- 동시에 콘솔 출력을 하면서 파이프 동작을 하게 하려 할때 !!
전면 & 후면
전면(foreground)
후면(background)
하나의 접속에서 여러개의 명령을 동시에 수행할 수 있는 방법은 ?
1980년대 산업에서 유닉스가 많이 퍼지기 시작했음.
이때 당시에는 더미 터미널이라고 하는 키보드랑 모니터만 있는 것이 있었음.
간단하게 문자를 보내고 결과를 받아 보는 단순한 하드웨어 였는데 이런 터미널이 여러개 접속되어야 하기 때문에
이런것을 처리 하기 위해 생긴 개념이 후면 (backgfound)임.
전면에 대해서 알아보자
일단 sleep 를 써보자.
sleep 5
로 입력을 하면 5초 동안. 아무런 입력을 할 수 없다.
즉 여기서 알수 있는것은 전면이란, 한 동작을 수행하기 위해선 다른 동작을 할 수 없는 상태를 말한다.
ls -R / > /dev/null 2>&1
동작중에 끄게 하기 위해선 control + c 를 누르면 된다.
자 그럼 전면을 후면으로 바꾸는 방법을 알아보자. !!!
그것은
ls -R / > /dev/null 2>&1 &
와 같이 사용하는 명령어 맨 끝에 & 만 입력 하면 된다.
후면에서 일어나는 동작을 보려면
jobs 라는 명령을 사용하면 된다.
후면에서 일어나는 작업은 연결된 창과 밀접한 연고나이 있기 때문에 새로운 콘솔 창을 연결하면 아무런 작업을 볼 수 없다.
control + c를 눌러도 종료가 되지 않는다.
그럼 종료하는 방법은
kill %번호
이다. 여기서 번호는 jobs를 통해서 확인 가능한 번호이다.
당근 후면 작업은 하나를 돌려 놓고 다른것을 돌릴 수 있다. 후면은 여러개 가능하다는 이야기 이다.
그럼 다른 터미널에서 후면 작업을 보는 방법은?
그것은 ps 명령을 통해서 보면 된다.
후면 작업을 하다가 로그아웃을 하면 작업이 있다 하며 바로 종료가 되지 않는다.
하지만 다시 로그아웃을 하면 나갈 수 있다.
그런데 문제는 이렇게 강제 종료를 하면 터미널 창을 닫으면 모든 작업이 종료 된다.
그래서 방책이 있다 그것은.
nohup 을 사용하면 된다.
fork
fork() 함수는 fork를 호출한 프로세스와 똑같은 생긴 새로운 프로세스를 만든다.
이때 커널이 각각의 프로세스에게 주는 값들이 있다.
fork를 호출한 함수에게는 자식의 pid값을 준다. 그리고 호출을 당한 프로세스에는 0값 즉, 성공을 알리는 값을 준다.
그래서 한 소스 안에서 자식과 부모의 동작을 기술 할 수 있다.
#include <stdio.h>
#include <unistd.h>
int main(void)
{
if(fork() == 0) // child process
{
system("sleep 3");
system("banner child");
system("ps -l");
exit(0);
}
else // parent process
{
system("sleep 8");
system("banner parent");
system("ps -l");
}
return 0;
}
결과
#### # # # # #####
# # # # # # # #
# ###### # # # #
# # # # # # #
# # # # # # # #
#### # # # ###### #####
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME COMD
1 S 549 19194 19187 0 158 20 50126700 82 4a866040 pts/tI 0:00 sh
1 S 549 19186 17631 0 158 20 4ec59ec0 10 50113040 pts/tI 0:00 fork
1 S 549 19187 19186 0 158 20 49d21840 10 5007e040 pts/tI 0:00 fork
1 R 549 19195 19194 1 178 20 49354cc0 37 - pts/tI 0:00 ps
1 S 549 19188 19186 0 158 20 49c0b1c0 82 50255040 pts/tI 0:00 sh
1 S 549 17631 17630 0 158 20 50036940 61 50454040 pts/tI 0:00 ksh
1 S 549 19191 19188 0 168 20 49d21c00 16 42c01040 pts/tI 0:00 sleep
1 S 0 17630 763 0 154 20 6042f700 45 4db158a8 pts/tI 0:00 telnetd
##### ## ##### ###### # # #####
# # # # # # # ## # #
# # # # # # ##### # # # #
##### ###### ##### # # # # #
# # # # # # # ## #
# # # # # ###### # # #
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME COMD
1 S 549 19186 17631 0 158 20 4ec59ec0 10 50113040 pts/tI 0:00 fork
1 Z 549 19187 19186 0 178 20 49d21840 0 - pts/tI 0:00 <defunct>
1 S 549 19208 19186 0 158 20 4391c700 82 50255040 pts/tI 0:00 sh
1 S 549 17631 17630 0 158 20 50036940 61 50454040 pts/tI 0:00 ksh
1 R 549 19209 19208 1 178 20 49c0b1c0 37 - pts/tI 0:00 ps
1 S 0 17630 763 0 154 20 6042f700 45 4db158a8 pts/tI 0:00 telnetd
위에 보면 Z 라는 상태가 존재 한다. 이넘은 좀비!!!! 다
근데 좀비란 무엇인가? 그것을 알아 보자.
모든 프로세스는 fork를 통해서 프로세스를 생성한다.
프로세스가 생성되면 모든것은 준비 상태이다.
시피유의 갯수는 프로세스의 갯수에 비해 절대 적인 수가 다르다. 그래서 시분할이라는 개념으로 cpu 시간을 나누어서 사용한다.
준비 -> 실행
되는 경우는 스케쥴러에 의해 선택을 받으면 이렇게 상태가 변경된다.
보통 cpu는 200ms 정도를 할당하고 시간이 초과 되면
실행 -> 준비
가 된다.
실행 -> 잠(sleep)
로 빠지는 경우가 있다. 그것은 실행중에 I/O 를 해야한 이벤트가 발생하면 동면(sleep) 상태로 변경하고 모든 I/O가 끝나면 다시
잠(sleep) -> 준비
로 된다.
실행을 하기 위한 런큐(RUN-Queue)라는 것이 존재한다.
이것은 큐형태의 자료구조에 실행할 프로세스가 대기한다.
이것이 중요한 이유는 성능측정을 위해서 실행큐에 얼마나 많은 프로세스가 있나로 성능을 측정할 수 있다.
sar라는 도구로 실행 큐에 남아 있는 프로세스 수를 측정한다.
이때 3개 미만 되면 시스템이 게안타~
즉, 실행 큐의 크기란 준비 상태에 있는 프로세스의 갯수다~
종료 하는 방법은 exit(0) 또는 강제 종료를 통해서 가능하다.
종료를 할때는 프로세스는 좀비(zombie)라고 하는 상태가 되었다가 최종적으로 종료 된다.
모든 프로세스는 부모 프로세스가 존재 한다. 절대로 고아 프로세스는 없다.
종료 시점에 프로세스가 하는 일은
- 자원 반남
메모리 반납
- 요까지 하면 모든 자원을 거의 반납을 했기 때문에
부모 프로세스에게 신호를 보냄
- 요럿케 하는건 약속. 모든 프로세스는 죽을때 부모 프로세스에게 신호를 보내도록 약속되어 있다.
- 신호를 보낸 후의 상태가 좀비(Zomble) 상태
부모가 종료 프로세스 신호를 받으면
- 부모가 자식 프로세스를 종료 시켜준다.
- 단 문제는 부모가 바빠서 종료를 안해 주면 자식 프로세스는 계속 적인 좀비 프로세스 상태로 되어 있다.
문제 !!!!
- 부모 프로세스가 수 많은 프로세스를 생성 시키고 난후 종료을 안시키면 심각한 문제가 발생한다.
- 유닉스에는 한번에 실행 시킬 수 있는 프로세스 갯 수 제한이 있다. 그런데 좀비가 많아 지면 시스템 관리자 조차도 아무런 명령을 실행 할 수 없다.
- 해결책은 !! 껐다 키는거 -> 이리 되면 유닉스는 파일 시스템에 심각한 문제가 발생 할 수 있다. 그래서 파일이 삭제 되거나 부팅이 되지 않은 문제가 발생한다.
- 이렇게 되면 자원은 남아 돌지만 좀비 프로세스만 많다.
- 이런 문제는 일반적으로 문제가 생기지 않지만. dbms 라던지 미들웨어는 좀비 프로세스를 만들 수 있기 때문에 관리자는 사전에 찾아서 문젝가 발생하지 않게 해야 된다. -> 재부팅 하지 않게
- 관리자는 반드시 좀비 프로세스 체크 해야 함.
좀비를 해결하는 문제
- 코드를 변경해야 하므로 제작사에게 알려서 고쳐 달라고 해야 한다.
ulimit -a
sysdef
ps
보이는 TIME 값은
할당된 CPU 시간이다.
-f
- 정보를 조금 더 자세히 알려고 할때.
- 명령이 완전하게 되어 보여진다.
- uid, ppid, C, STIME를 알수 있다.
- uid, 와 ppid를 중요한 정보를 알 수 있음.
- STIME : 시작 시간.
-l
-e
- 내 프로세스 뿐만 아니라 유닉스 에서 돌아가는 모든 프로세스를 보여주는 옵션.
좀비프로세스를 알아보는 쉘 프로그래밍
ppid = `ps -el | awk '$2 == "Z" {print $5}'`
echo "PPID = $ppid"
ps -ef | grep $ppid
kill
프로세스에게 신호를 보내는 명령
근데 주로 프로세스를 죽이는 명령으로 쓰기 때문에 킬 하는 명령, 죽이는 명령이라 기억한다.
특별히 안쓰면 신호 번호 15번 TERM신호가 전송된다.
신호 목록
INT
QUIT
- control + \
- 방어 가능
- 코아 파일을 생성시키게 하는 신호
KILL
TERM
CHLD
- STOP
- TSTP
일반적으로 종료 할때는 15번 신호 TERM이면 되지만, 안되는 경우는 9번 신호 kill 신호를 보내면 죽는다.
하지만 다른 사용자가 만든 프로세스는 종료가 불가능 하다. 단, 역시나 관리자가 대빵이다!! 가능하다.
데몬프로세스
서비스
시스템이 시작하면 자동으로 시작 되어 실행되는 프로세스
TTY가 ? 인 녀석이 데몬 프로세스이다.
ps -ef | grep inetd
라고 쳐서 inetd를 프로세스 정보를 보자.
inetd 프로세스는 우리가 접속하는 telnet 과 연관이 있는데 telnetd 프로세스의 부모가 inetd 음.
프로세스 통신
2개의 프로세스가 통신하는 방법
-> 단방향 통신임(One -Way)
2개 이상의 프로세스가 통신하는 방법 중에 메세지 큐, 공유 메모리, 세마포어 가 있음
-> both-Way
Message Queue
- 길이가 짧은 거에 사용 (1KB)
- 속도 느림
- 구현이 간단하고 쉬움.
Shared Memory
Semaphore
named pipe
소스
fifo1
include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#define BUFFER_SIZE PIPE_BUF
#define TEN_MEG (1024 * 1024 * 10)
int main()
{
int pipe_fd;
int res;
char buffer[BUFFER_SIZE + 1];
pipe_fd = open("mypipe", O_WRONLY);
if (pipe_fd != -1) {
while(1) {
write(1,"Talker>",8);
pipe_fd = open("mypipe", O_WRONLY);
if (pipe_fd != -1) {
while(1) {
write(1,"Talker>",8);
fgets(buffer,BUFFER_SIZE,stdin);
if(strcmp(buffer,"end\n")==0)
break;
res = write(pipe_fd, buffer, strlen(buffer));
}
(void)close(pipe_fd);
}
else {
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
fifo2
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#define BUFFER_SIZE PIPE_BUF
int main()
{
int pipe_fd;
int res;
char buffer[BUFFER_SIZE + 1];
int bytes_read = 0;
memset(buffer, '\0', sizeof(buffer));
pipe_fd = open("mypipe", O_RDONLY);
if (pipe_fd != -1) {
pipe_fd = open("mypipe", O_RDONLY);
if (pipe_fd != -1) {
while (1) {
res = read(pipe_fd, buffer, BUFFER_SIZE);
if(res <=0)
break;
printf("%s",buffer);
}
(void)close(pipe_fd);
}
else {
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
mkfifo
- 위의 소스를 사용하면 2 프로세스간의 통신을 보여주는 소스이다.
- 일반 mypipe를 생성하면 fifo2 소스가 대기 하지 않고 바로 종료 된다. 그리고 아무리 내용을 fifo1에 입력을 해도 내용은 입력되지 않고 다만 mypipe 파일이 내용이 커진다.
- 하지만 mkfifo 를 사용하여 mypipe를 생성하면 fifo2가 종료 되지 않고 살아 있다. 그리고 fifo1에서 내용을 입력하면 fifo2에 내용을 보여준다.
IPC key
키값이 같으면 같은 공유 메모리를 사용한다.
ipcs
IPC 상태
ipcrm
IPC 강제 삭제
추가
총괄 실습
현재 수행 하는 프로세스 갯수 세기
ps -ef | grep jsp30 | grep -v grep | awk '{print $8, $2}' | sort +2 -n > jsp30ps.log
ps -ef | awk '$1 == "jsp30"{print $8, $2}' | sort +2 -n > jsp30ps.log
이 글은 스프링노트에서 작성되었습니다.