본문 바로가기
리눅스/Part 1 - Learning The Shell

리눅스 기초 | 10-2. 프로세스

by 객잔주인 2024. 6. 3.

해당 포스팅은 William E. Shotts, Jr. 의 오픈소스 저서 The Linux Command Line(링크)를 번역한 내용입니다


 

시그널(Signals)

$\texttt{kill}$ 명령어는 프로세스를 "죽이기" 위해 사용됩니다.

먼저 $\texttt{yes}$를 백그라운드에서 실행하면 쉘은 이 백그라운드 프로세스의 jobspec과 PID를 출력합니다. 다음 프로세스를 종료하기 위해 $\texttt{kill}$ 명령어에 프로세스의 PID를 인자로 입력했습니다. 여기서 PID 대신 $\texttt{%1}$처럼 jobspec을 입력하는 것도 가능합니다.

 

굉장히 간결하고 직선적인 과정 같지만 뒤에 숨겨진 일들이 있습니다. $\texttt{kill}$ 명령어는 프로세스를 죽이지는 않습니다. 대신 프로세스에 시그널(signal)을 보냅니다. 시그널은 운영체제가 프로그램과 소통하는 방식들 중 하나입니다. 이미 봤던 $\texttt{Ctrl-c}$와 $\texttt{Ctrl-z}$도 시그널의 일종입니다. 터미널이 이런 키 입력을 받으면 포어그라운드에 있는 프로그램에 시그널을 보냅니다. $\texttt{Ctrl-c}$의 경우에는 $\texttt{INT}$ (interrupt)라는 시그널을 보내고, $\texttt{Ctrl-z}$는 $\texttt{TSTP}$ (terminal stop)이라는 시그널을 보냅니다. 반대로 프로그램은 수신된 시그널에 따라 조치를 취할 수 있습니다. 이러한 기능 덕분에 프로그램은 종료 시그널을 받을 때 작업을 저장하는 등의 작업을 할 수 있습니다.

$\texttt{kill}$을 사용해 프로세스에 시그널 전송

$\texttt{kill}$ 명령어는 프로그램에 시그널을 보낼 때 사용됩니다. 기본적인 문법은 다음과 같습니다:

시그널이 명시되지 않으면 기본적으로 $\texttt{TERM}$ (terminate) 시그널이 전송됩니다. $\texttt{kill}$ 명령어에 자주 사용되는 시그널은 다음과 같습니다:

 

Table 10-4: 자주 사용되는 시그널

번호 이름 의미
1 $\texttt{HUP}$ Hangup. HUP 신호는 터미널이 전화선을 통해 원격 컴퓨터에 연결되어 있을 때 사용되던 과거의 자취입니다. 터미널 연결이 끊어지면 $\texttt{HUP}$ 시그널이 프로그램에 전송되어 터미널 연결이 끊어졌음을 알립니다. 현재도 터미널 세션을 닫으면 포어그라운드에서 실행중이 프로그램에 $\texttt{HUP}$ 시그널이 전송됩니다.이 신호를 받은 프로그램은 기본적으로 종료됩니다.

$\texttt{HUP}$ 시그널은 많은 데몬 프로그램에서 재초기화를 일으킬 때에도 많이 사용됩니다. 데몬 프로그램에 $\texttt{HUP}$ 시그널이 전송되면 데모는 재시작되면서 설정 파일을 다시 읽습니다.
2 $\texttt{INT}$ Interrupt. $\texttt{INT}$는 $\texttt{Ctrl-c}$와 같은 기능을 하는 시그널입니다. 보통 프로그램을 종료합니다.
9 $\texttt{KILL}$ $\texttt{KILL}$은 특별한 시그널입니다. 다른 시그널들은 프로그램에 직접 전송되어 프로그램이 그 시그널에 맞게 설계된대로 조치를 취한다면 $\texttt{KILL}$은 프로그램으로 직접 전송되지 않습니다. 대신 커널이 즉시 프로세스를 종료합니다. 프로세스가 이런 방식으로 종료되면 프로그램이 "청소"하거나 작업을 저장하지 못하게 됩니다. 이런 이유에서, $\texttt{KILL}$은 프로그램이 정상종료가 되지 않을 때 사용할 최후의 수단으로 남겨두는 것이 좋습니다.
15 $\texttt{TERM}$ Terminate. $\texttt{kill}$ 명령어가 보내는 기본 시그널로, 프로그램이 최소한 이 시그널을 받을 수 있는 상황이라면 해당 프로그램을 종료할 수 있습니다.
18 $\texttt{CONT}$ Continue. $\texttt{STOP}$이나 $\texttt{TSTP}$ 시그널로 멈춘 프로세스를 다시 가동합니다. $\texttt{bg}$와 $\texttt{fg}$ 명령어가 보내는 시그널입니다.
19 $\texttt{STOP}$ Stop. 프로세스가 종료되지 않고 정지하도록하는 시그널입니다. $\texttt{KILL}$ 시그널과 마찬가지로, 목표 프로세스에 전송되지 않고, 그렇기 때문에 프로세스가 이 시그널을 무시할 수 없습니다.
20 $\texttt{TSTP}$ Terminal Stop. $\texttt{Ctrl-z}$가 입력되었을 때 전송되는 시그널입니다. $\texttt{STOP}$ 시그널과 다르게 $\texttt{TSTP}$은 프로그램이 수신하기 때문에 이 시그널을 무시하게 될 수 있습니다.

 

$\texttt{kill}$ 명령어를 사용해 보겠습니다:

이 예제에서는 $\texttt{yes}$ 프로그램을 백그라운드에서 실행한 뒤 $\texttt{kill}$을 사용해 $\texttt{HUP}$ 시그널을 전송했습니다. $\texttt{yse}$ 프로그램이 종료되고 터미널은 해당 프로세스가 "Hangup" 되었음을 알립니다. 이 알림을 띄우려면 $\texttt{Enter}$를 몇 번 더 쳐야 할 수 있습니다. $\texttt{kill}$ 명령어에 시그널은 번호나 이름, 혹은 앞에 접두어 $\texttt{SIG}$를 붙인 이름 중 어느 것을 넣어도 동작합니다.

시그널을 바꿔가며 위 예제를 반복해 보세요. PID 대신 jobspec을 사용할 수 있다는 것도 잊지 마시기 바랍니다.

 

프로세스는 파일처럼 소유자가 있고, $\texttt{kill}$을 사용해 시그널을 전송하기 위해서는 해당 프로세스의 소유자(혹은 슈퍼유저)여야 합니다.

 

위에 언급된 시그널 외에도 시스템에 자주 사용되는 시그널들이 있습니다:

 

Table 10-5: Other Common Signals

번호 이름 의미
3 $\texttt{QUIT}$ Quit. 나가기
11 $\texttt{SEGV}$ Segmentation violation. 이 시그널은 프로그램이 허가되지 않은 메모리에 쓰기 작업을 수행하려고 할 때 전송됩니다.
28 $\texttt{WINCH}$ Window Change. 창 크기가 바뀔 때 시스템이 보내는 시그널입니다. $\texttt{top}$이나 $\texttt{less}$와 같은 몇몇 프로그램들은 이 시그널을 받아 창 크기에 맞게 레이아웃을 바꿉니다.

 

궁금하다면 아래 명령어를 통해 전체 시그널 목록을 확인할 수 있습니다:

 

$\texttt{killall}$을 사용해 여러 프로세스에 시그널 전송

$\texttt{killall}$ 명령어를 사용하면 명시된 프로그램 이름이나 사용자명과 매칭되는 여러 프로세스에 시그널을 전송하는 것도 가능합니다. 우선 명령어의 문법을 보고 가겠습니다:

이 명령어를 사용해 보기 위해 $\texttt{yes}$ 프로그램을 여러 개 실행시킨 후 모두 종료해 보겠습니다.

$\texttt{kill}$과 마찬가지로 $\texttt{killall}$ 또한 슈퍼유저 권한이 있어야 시그널을 전송할 수 있습니다.

시스템 종료하기

시스템을 종료하기 위해서는 시스템의 모든 프로세스를 차례로 종료하고, 탑재된 모든 파일 시스템을 동기화하는 등의 필수적인 작업들을 해야 합니다. 종료 작업을 위해 사용하는 명령어는 $\texttt{halt}$, $\texttt{poweroff}$, $\texttt{reboot}$, $\texttt{shutdown}$이 있습니다. 처음 세 개의 명령어는 이름에서 그 기능을 유추할 수 있고, 일반적으로 추가적인 옵션 없이 사용됩니다. 예시를 보겠습니다:

$\texttt{shutdown}$ 명령어는 조금 더 흥미로운데, $\texttt{shutdown}$에 옵션으로 $\texttt{halt}$, $\texttt{poweroff}$, $\texttt{reboot}$를 옵션으로 넣고 이 작업을 실행하기까지의 시간 딜레이를 줄 수 있습니다. 시스템을 halt 시키기 위해서 이렇게 자주 사용됩니다:

혹은 다음과 같이 reboot 할 수 있습니다:

딜레이는 다양한 방식으로 명시될 수 있습니다. 자세한 내용은 $\texttt{shutdown}$의 매뉴얼 페이지를 확인해 보세요. $\texttt{shutdown}$ 명령이 실행되면 로그인 되어있는 모든 사용자에게 메시지가 전파됩니다.

 

프로세스 관련 명령어

프로세스를 모니터링하는 것은 중요한 시스템 관리 업무이므로 이를 위한 다양한 명령어가 존재합니다:

 

Table 10-6: 프로세스 관련 명령어들

명령어 설명
$\texttt{pstree}$ 프로세스 목록을 트리 형태로 출력하여 각 프로세스의 부모-자식 관계를 보여줍니다.
$\texttt{vmstat}$ 메모리, 스왑, 디스트 I/O 등의 시스템 리소스 사용 상태에 대한 스냅샷을 출력합니다. 지속적인 업데이트를 원할 경우 시간 간격을 지정할 수 있습니다. 예) $\texttt{vmstat 5}$. $\texttt{Ctrl-c}$를 입력해 종료할 수 있습니다.
$\texttt{xload}$ 시스템 부하를 그래프로 보여주는 그래픽 프로그램입니다.
$\texttt{tload}$ $\texttt{xload}$와 비슷하지만 그래프를 터미널 내에 표시합니다.

 

요약

최신 시스템들은 여러 프로세스를 관리하는 메커니즘을 가지고 있습니다. 리눅스는 다양한 프로세스 관리 툴을 제공합니다. 리눅스가 서버용 운영체제로 가장 많이 사용되고 있기 때문에, 리눅스의 프로세스 관리 편의성이 간접적으로 증명된 바나 다름없습니다. 그러나 다른 시스템들과는 다르게 리눅스는 커맨드 라인 툴들에 거의 전적으로 의존합니다. 리눅스에도 GUI 기반의 프로세스 관리 도구가 있지만, 빠른 속도와 시스템 자원을 덜 사용하는 커맨드 라인 툴이 더 선호됩니다. GUI 기반의 툴이 더 예뻐 보일 수는 있지만, 그들 자체로 시스템에 상당한 부하를 발생시켜 자원관리라는 본래의 목적을 상실하게 됩니다.