현대 운영체제들은 여러 프로그램들 사이사이를 굉장히 빠르게 이동함으로써 여러 작업을 실행하는 멀티태스킹 방식이다.
리눅스 커널은 프로세스를 통해 이를 관리하는데, 리눅스가 CPU 를 사용하기 위해 차례를 기다리는 프로그램들을 구조화한 것이다.
컴퓨터는 가끔 느려지거나 응답을 멈추는 경우가 있는데, 커맨드라인에서 이런 프로세스들을 확인할 수 있다.
프로세스는 어떻게 동작하는가
시스템이 구동 될 때, 커널은 /etc 에 위치한 init 이라는 스크립트를 실행함으로써 시스템 서비스들을 차례대로 시작시킨다.
이 서비스들은 데몬 프로그램(백그라운드)으로 구현되어 있기 때문에 로그인하지 않은 상태에서도 필요 작업들을 수행한다.
프로그램은 프로그램을 실행시킬 수 있는데, 이를 부모와 자식 프로세스라고 표현한다.
커널은 이러한 프로세스들을 구조화시킨 형태로 유지하기 위해서 PID 라는 프로세스 ID 정보를 가지며, 항상 init 이 1번 PID 를 할당 받는다.
ps 명령어로 프로세스 보기
여러 프로세스들을 확인하는 명령어로는 간단하게 ps 가 있다.
ps 에는 여러 옵션들이 있지만, 옵션 없이 실행시킬 경우 현재 터미널과 관련된 프로세스만을 보여준다.
결과에서 보여주는 필드들 중 PID 는 프로세스 ID, TTY 는 프로세스를 제어하는 터미널, TIME 은 프로세스의 cpu 사용 시간을 나타낸다.
시스템 전체의 상황을 살펴보기 위해서는 x 옵션을 추가하면 된다.
ps # 현재 터미널과 관련된 프로세스
ps x # 전체 시스템
시스템은 많은 프로세스들을 실행시키고 있기 때문에 ps x 의 결과는 길게 나오기 마련인데, 파이프라인으로 넘겨 less 등과 같이 사용할 수 있다.
ps x 에서는 STAT 이라는 새로운 필드도 추가해서 보여주는데, 프로세스의 현재 상태를 나타내며 아래의 표와 같은 의미를 갖는다.
상태 | 의미 |
D | 인터럽트 불가능한 수면 상태, 입출력을 기다리는 중 |
R | Running, 실행 중이거나 실행 대기 중 |
S | Sleeping, 키 입력이나 네트워크 패킷과 같은 이벤트 대기 중 |
T | Terminated, 종료 요청을 받았거나 종료된 상태 |
X | 죽은 프로세스 |
Z | Zombie, 부모 프로세스에 의해 정리되지 않은 종료된 자식 프로세스 |
< | 높은 우선순위 프로세스, 중요성에 따라 cpu 자원을 더 소비 |
N | 낮은 우선순위 프로세스 |
L | 데이터를 메모리에 유지 중인 프로세스 |
s | 세션 리더 |
l | 멀티 쓰레드 프로세스 |
+ | foreground 프로세스 그룹 |
또다른 인기 있는 옵션들에는 aux 나 ef 등이 있다.
top 으로 프로세스 변화 보기
ps 명령어는 명령어가 실행된 순간의 프로세스 상태들에 대해서 정적인 정보만을 제공하며, top 은 시스템 활동을 실시간으로 확인할 수 있다.
top 프로그램은 활동 순으로 나열된 프로세스들을 지속적으로 갱신하면서 보여준다.
위에는 시스템에 대한 전반적인 요약을 보여주며, 아래에 테이블로써 CPU 를 사용하는 순으로 프로세스들을 정렬해서 보여준다.
top 을 통해 모니터링 중인 상태에서 h 를 누르면 다양한 추가적인 기능들에 대한 도움말을 볼 수 있다.
top 역시 하나의 프로세스가 되기 때문에 top 의 결과에서 top 프로세스도 같이 등장하며, 시스템 리소스를 굉장히 적게 사용하기 때문에 시스템 저하를 적게 일으키는 좋은 프로그램이다.
최근에는 htop 이라는 조금 더 사용자에게 친화적인 도구를 사용하기도 한다.
프로세스 제어
ps 나 top 등을 통해 어떤 프로세스가 있는지 확인할 수 있으니, 프로세스를 종료하거나 대기시키는 것에 대해서도 알아야 한다.
gedit 은 텍스트를 편집하는 프로그램을 띄워주는데, 실행 후 터미널을 보면 텍스트 에디터가 종료되지 않을 때 까지 대기 중임을 확인할 수 있다.
에디터를 종료할 경우 다시 프롬프트로 돌아오게 된다.
에디터가 실행 중인 상태에서 터미널로 돌아와 타이핑을 할 경우 출력은 되더라도 반응이 없지만, ctrl + C 를 누를 경우 에디터가 닫히며 프로그램이 종료된다.
대부분의 CLI 프로그램들은 ctrl + C 로 프로그램을 중단시킬 수 있다.
백그라운드로 실행하기
gedit 프로그램을 실행하고 싶지만, 쉘 프롬프트로도 바로 돌아가고 싶을 경우에는 프로그램을 백그라운드로 실행시킬 수 있다.
명령어 뒤에 & 를 붙여서 실행시킬 경우 쉘이 프로그램의 종료를 대기하지 않으며 쉘 프롬프트에 대해서 평상시처럼 접근 할 수 있게 된다.
gedit &
위와 같이 프로그램을 백그라운드로 실행시킬 경우 stdout 에 PID 를 같이 출력해준다.
이 PID 를 알고 있으면 백그라운드 프로그램에 대해 커맨드라인에서 프로세스를 죽이거나 다시 foreground 로 전환시킬 때 편리하다.
백그라운드에서 프로그램이 실행될 경우, ps 로 터미널의 프로세스들을 출력 시 해당 프로그램도 같이 나오게 된다.
포어그라운드로 전환하기
위에서 실행한 백그라운드 프로세스를 다시 포어그라운드로 가져오는 명령어로는 fg 가 있다.
어떤 프로세스를 포어그라운드로 가져올 것인지에 대해서는, 아래와 같이 %(작업번호) 혹은 %(프로세스이름) 을 인자로 넣어주면 된다.
작업번호를 확인하기 위해서는 jobs 라는 명령어를 사용한다.
fg %1
fg %gedit
프로세스 일시정지 시키기
지금까지는 대부분 ctrl + C 를 통해 프로세스를 종료하는데에 익숙했겠지만, 가끔 포어그라운드 프로세스를 백그라운드로 이동시키기 위해 일시 정지 시킬 필요가 있다.
ctrl + Z 를 누를 경우 프로세스가 종료가 아닌 일시정지가 되는데, gedit 의 경우 실행된 프로그램이 응답없음과 같이 말을 듣지 않는 상태가 된다.
실제로 ps x 를 통해 STAT 을 확인해도 Terminated 라고 뜨며, 죽은 것처럼 취급되지만, fg 명령어를 사용해서 포어그라운드나 bg 명령어로 백그라운드로 복원시킬 수 있다.
bg 는 fg 와 비슷하게 작업 번호를 확인해서 인자로 넣어주면 된다.
시그널
kill 명령어는 프로세스를 강제로 종료시킨다. 위에서 나왔던 좀비 프로세스나, 응답 없음, 비정상적으로 동작하는 프로세스들의 실행을 끝내게 해준다.
gedit 을 백그라운드로 실행시킨 뒤, 포어그라운드로 가져와서 ctrl + C 할 수도 있지만, 아래처럼 PID 를 확인하여 kill 로 바로 종료시킬 수도 있다.
kill %1
kill 3284(UID)
사실 kill 은 프로세스를 직접 종료시키는 것이 아니라, 프로세스에 종료하라는 시그널을 보내 종료되게끔 한다.
마찬가지로 ctrl + C 와 ctrl + Z 역시 프로세스에게 각각 해당하는 시그널을 보내 인터럽트시키거나, 정지 시키는 것이다.
프로세스들은 지속적으로 입력되는 시그널에 대기하는 로직이 존재하여, 받은 시그널에 따라 행동하는 것 뿐이다.
따라서 프로그램을 작성 시 입력되는 시그널에 귀기울이다가, 인터럽트 등 종료 시그널을 받았을 때 어떤 작업을 수행하게끔 하는 것도 가능하다.
kill 로 시그널 보내기
kill -signal PID
옵션으로 주는 시그널은 굉장히 다양하게 있는데, kill -l 로 목록을 확인할 수 있다.
시그널 옵션을 제외할 경우는 기본적으로 TERM(15) 시그널을 보내는데, 이는 프로그램이 시그널에 대기할 수 있을 정도로 살아있다면 종료시키는 옵션이다.
또다른 많이 쓰이는 옵션으로는 KILL(9) 가 있는데, 이는 커널로 하여금 프로세스를 죽이게 한다.
이건 정말 프로그램 내에서 로직이 꼬여서 멈춰버리는 등 TERM 등과 같은 시그널이 실패한 경우에 강제 종료시키는 방법이다.
그 외로도 HUP, INT, STOP, CONT, QUIT, TSTP, SEGV 등 다양한 시그널이 있는데, 찾아보도록 하자.
'STUDY > Linux' 카테고리의 다른 글
[리눅스] 쉘 환경 (0) | 2021.07.21 |
---|---|
[리눅스] Permission (0) | 2021.07.05 |
[리눅스] 커맨드라인 키보드 기법 (0) | 2021.07.01 |
[리눅스] 확장 제어 (0) | 2021.06.30 |
[리눅스] 확장 (0) | 2021.06.28 |