오늘은... 이런 분들께 도움이 되면 좋겠다
프로그램을 실행 시켰는데 이게 진짜 실행된건지 확인해보고 싶다 🖐
자신이 실행시킨 프로그램이 안죽어본 적이 있다 🖐
왜 안죽는지 모르겠다 🖐
좀비 프로세스를 만들고 당황한적 있다 🖐🖐🖐
바로 나야나
리눅스 환경에서 프로그램을 짜봤다하면 한번쯤은 들어봤을
process(프로세스)와 PID에 대해서 알아보고자 한다
그리고 이를 확인할 수 있는 명령어도 정리하려고 한다
1. Process(프로세스)란?
프로세스란 단어는 많이 익숙할텐데, 딱 뭐라고 정의하기는 어려운 단어다
보통 프로그램과 많이 비교가 된다
프로그램은?
하드 디스크에 저장되어 있는 실행코드
프로세스는?
프로그램을 구동하여 프로그램 자체와
프로그램의 상태가 메모리 상에서 실행되는 작업 단위
즉, 실행시킨 프로그램을 뜻한다
(여러 개의 프로그램을 띄워서 사용하면 멀티프로세싱 -_-a)
(1) 프로세스 상태
운영체제를 공부하다보면 항상 접하는 프로세스 상태
좀 이론적인 얘기를 정리해보자면...
위에서 설명했듯이 프로그램을 실행한게 프로세스인데,
요걸 관리해주는 운영체제일거다
운영체제에서 프로그램을 어떻게 실행시키고 언제 실행시키고 종료하는지가
프로세스 상태라고 한다
그림에서 나와있는 것 처럼 5가지의 상태가 있다
실행(running) : 프로세스가 CPU를 차지하여 명령어들이 실행되는 단계
생성(create) : 프로세스가 생성되는 중
준비(ready) : 프로세스가 CPU를 사용하고 있지는 않지만 언제든지 사용할 수 있는 상태로, CPU가 할당되기를 기다리고 있다. 일반적으로 준비 상태의 프로세스 중 우선순위가 높은 프로세스가 CPU를 할당받는다.
대기(waiting) : 보류(block)라고 부르기도 한다. 프로세스가 입출력 완료, 시그널 수신 등 어떤 사건을 기다리고 있는 상태를 말한다.
종료(terminated) : 프로세스의 실행이 종료된 단계
(↑ 위키백과에서 가져옴)
암튼 이런 단계들이 있는데,
우리한테 필요한거는 실행/종료 상태이다
그리고 리눅스에서는 이 프로세스 상태를 조회할 수 있는
명령어를 갖고 있다 → ps
요건 아래에서 설명하겠다
(2) PID (Process ID)
말 그대로 프로세스 ID이다
운영체제가 관리하기 위해 붙여놓은 식별 번호이다
말은 거창하지만 사람한테 주민번호 할당한 것 처럼
프로세스를 구분하기 위해 사용하는 ID이다
2. PS (Process Status)
프로세스 상태를 알 수 있는 명령어는 ps라는 것이 있다
커맨드라인에 help를 해보면
CLI> ps --help
Usage:
ps [options]
Try 'ps --help <simple|list|output|threads|misc|all>'
or 'ps --help <s|l|o|t|m|a>'
for additional help text.
For more details see ps(1).
이렇게 세상 간단한 설명이 있다
전체 설명을 보고 싶으면 옵션 a를 추가해준다
CLI> ps --help a
Usage:
ps [options]
Basic options:
-A, -e all processes
-a all with tty, except session leaders
a all with tty, including other users
-d all except session leaders
-N, --deselect negate selection
r only running processes
T all processes on this terminal
x processes without controlling ttys
Selection by list:
-C <command> command name
-G, --Group <GID> real group id or name
-g, --group <group> session or effective group name
-p, p, --pid <PID> process id
--ppid <PID> parent process id
-q, q, --quick-pid <PID>
process id (quick mode)
-s, --sid <session> session id
-t, t, --tty <tty> terminal
-u, U, --user <UID> effective user id or name
-U, --User <UID> real user id or name
The selection options take as their argument either:
a comma-separated list e.g. '-u root,nobody' or
a blank-separated list e.g. '-p 123 4567'
Output formats:
-F extra full
-f full-format, including command lines
f, --forest ascii art process tree
-H show process hierarchy
-j jobs format
j BSD job control format
-l long format
l BSD long format
-M, Z add security data (for SELinux)
-O <format> preloaded with default columns
O <format> as -O, with BSD personality
-o, o, --format <format>
user-defined format
s signal format
u user-oriented format
v virtual memory format
X register format
-y do not show flags, show rss vs. addr (used with -l)
--context display security context (for SELinux)
--headers repeat header lines, one per page
--no-headers do not print header at all
--cols, --columns, --width <num>
set screen width
--rows, --lines <num>
set screen height
Show threads:
H as if they were processes
-L possibly with LWP and NLWP columns
-m, m after processes
-T possibly with SPID column
Miscellaneous options:
-c show scheduling class with -l option
c show true command name
e show the environment after command
k, --sort specify sort order as: [+|-]key[,[+|-]key[,...]]
L show format specifiers
n display numeric uid and wchan
S, --cumulative include some dead child process data
-y do not show flags, show rss (only with -l)
-V, V, --version display version information and exit
-w, w unlimited output width
--help <simple|list|output|threads|misc|all>
display help and exit
For more details see ps(1).
정말 많은 옵션이 있군!
이 중 내가 자주 쓰는 옵션은 아래와 같다
참고) -가 붙은 옵션과 안 붙은 옵션은 다르게 쓰임
옵션명 | 설명 |
-e | all processes 현재 커널에서 사용하는 모든 프로세스들 보고싶을 때 |
-L | possibly with LWP and NLWP columns LWP는 경량 프로세스를 뜻함 프로그램에서 돌고 있는 스레드 다 보고 싶을 때 씀 |
-f | full-format, including command lines 시간 정보 같은거도 다 볼 수 있음 |
CLI> ps -eLF | grep {Process 이름}
요렇게 많이 쓴다
옵션이 많으니까 필요한거 찾아서 쓰면 될듯.
참고) grep 명령은 많은 정보에서 필요한거만 찾고 싶을 때 씀
그러면 ps 명령어로 뭐를 확인할 수 있느냐....를 보기위해
아래와 같이 커맨드를 입력해보자
CLI> ps -f
UID PID PPID C STIME TTY TIME CMD
{USER} 764 47766 0 18:02 pts/20 00:00:00 ps -f
{USER} 47766 47765 0 10:00 pts/20 00:00:00 -csh
UID..? PID는 뭔데..?
각 열이 뭘 뜻하는지 간단설명 하자면
머선 열 | 설명 |
USER | 프로세스 소유자 이름 (계정 이름이라고 볼 수 있다.) |
UID | USER ID 말 그대로 소유자 ID 되시겠다 |
PID | Process ID 요것이 바로 PID!! |
PPID | Parent Process ID 요것이 부모 프로세스 ID ㅋ 좀비 프로세스가 생겼을 때 부모 프로세스 ID를 죽이라는 말을 들어봤을 텐데 그때 PPID를 조회하면 됨 |
STIME | Start Time 프로세스가 시작된 시간 |
TTY | Tele Typewriter? Teletype? 프로세스가 실행된 터미널 "종류/번호" |
TIME | CPU를 사용한 총 시간 (프로그램이 실행되기 전에는 0이라고 함) |
CMD | 프로세스 이름 또는 명령어 사용 ex) ./test 하면 test로 나오겠죵? 위의 예제에서 "ps -f" 명령어를 사용해서 CMD에 표시된거도 보임 |
LWP | Light weight process 위에서 잠깐 얘기했던 경량 프로세스인데, 지금 떠있는 스레드를 뜻하는거임 |
그럼 이쯤에서 예시하나를 실행해보겠다
아주 간단한 10초마다 시간찍는 프로그램이다
#include <ctime>
#include <csignal>
#include <thread>
#include <chrono>
using namespace std;
bool signal_flag = true;
string getNowTime()
{
time_t now = time(0);
return ctime(&now);
}
void signalHdlr(int signum)
{
cout << "\nSignal: " << signum << endl;
signal_flag = false;
}
int main ( )
{
signal(SIGINT, signalHdlr);
signal(SIGTERM, signalHdlr);
signal(SIGQUIT, signalHdlr);
signal(SIGKILL, signalHdlr);
int active_cnt = 0;
while( signal_flag )
{
if( active_cnt >= 10 )
{
cout << getNowTime() << endl;
active_cnt = 0;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
active_cnt++;
}
return 0;
}
sinal 처리만 추가해준 간단한 프로그램이다
요걸 make하고 실행시키면
CLI> ./test_r
Tue Jun 8 11:11:20 2021
Tue Jun 8 11:11:30 2021
Tue Jun 8 11:11:40 2021
.....
요렇게 시간을 찍는데, 프로세스가 어떤 상태인지 봐보고 싶다면?
ps 명령어로 보면 된다
CLI> ps -eLF | grep test_r
{UID} 11421 10718 11421 0 1 4186 988 22 11:22 pts/19 00:00:00 ./test_r
{UID} 11433 738 11433 0 1 29204 984 5 11:22 pts/9 00:00:00 grep -n --exclude=tags test_r
이렇게 나온다.
커맨드로 치니까 위에 필드가 안나와서 ㅠㅠ 왜 안나오지...
UID | PID | PPID | LWP | STIME | TTY | TIME | CMD |
{USER ID} | 11421 | 10718 | 11421 | 11:22 | pts/19 | 00:00:00 | ./test_r |
매칭시켜서 설명하면 요러하다
근데 상태를 볼 수 있는건 알겠는데 스레드별로 보고 싶은데
그건 어떻게 보지???? 할 수 있는데 그럴 때 쓰는 명령어가 또 있다
3. PSTACK(Process Stack)
바로바로 pstack이라는 명령어이다
스레드가 어디서 블록되어있는지 궁금하거나,
프로세스를 분명히 종료시켰는데, 남은 스레드가 있다거나!!
프로세스가 지금 무슨 짓을 하고 있는지 볼 수 있다
사용방법은 아주 간단하다
CLI> pstack {PID}
CLI> pstack {LWP}
ps 명령어로 확인한 PID를 입력만 해주면 된다
CLI> pstack 12759
#0 0x00002b4bbee2abc0 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:81
#1 0x000000000040125c in std::this_thread::sleep_for<long, std::ratio<1l, 1l> > (__rtime=...) at /usr/local/gcc-4.9.4/include/c++/4.9.4/thread:281
#2 0x0000000000400f09 in main () at main.cpp:38
이렇게 스레드에 대한 추적(?)한 부분을 보여준다
참고) 프로세스 소유자거나 root 계정에서만 수행 가능
#0은 위 예시에서 sleep 함수를 사용한거고
#1은 std::this_thread 사용한 부분이다
#2는 main 스레드를 보여준다
두 번째 필드는 스레드 ID를 뜻한다 (TID)
이건 간단한 프로그램이라 3개의 스택만 보이는데,
큰 프로그램을 다루다보면 음청 많은 스레드가 뜰텐데,
그 때 ps나 pstack 명령어 등을 이용해서 추적해보자
4. KILL (죽여)
오늘 마지막으로 설명할 명령어는 kill 이다
말그대로 죽이는거다 ㅎㄷㄷ
프로세스에 시그널 처리를 제대로 안하거나
잘못된 코드를 짠 경우에는 제대로 종료가 안되는 경우가 종종 있다
그냥 무시하게 되면, CPU가 못버틸 수도 있으니까
제대로된 종료를 해주는게 좋다!
좀비 프로세스도 이런 경우에서 생기기 마련이다
CLI> kill -{SIGNAL 번호} {PID}
사용방법은 요렇게 PID를 죽여줘! 로 쓰인다
SIGNAL 번호는 얘를 어떻게 죽여줄까?라는 번호이고,
1부터 시작하는 리스트로 이루어져있다
kill 명령어로 요 리스트를 볼 수 있다
CLI> kill -l
HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT
STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH POLL PWR SYS RTMIN RTMIN+1 RTMIN+2
RTMIN+3 RTMAX-3 RTMAX-2 RTMAX-1 RTMAX
이렇게 -l 옵션을 줘서 사용할 수 있는 signal 목록을 볼 수 있는데,
보통 프로그램을 많이 종료할 때 사용하는건 KILL(9번째꺼)이다
참고) 1부터 시작하는 인덱스를 가진다
CLI> kill -9 11421
실제 사용하면 요렇게랄까!?
이러면 된다.. 잘 종료가 되었는지는 ps 명령어를 통해 확인 가능하다
(1) SIGNAL
kill 명령어를 그래도 한번쯤 쓴다면 signal이 뭐뭐 있는지는 봐야할 것 같다
한번 읽어보는거에 의의를 두기 위해, man 페이지만 캡쳐해서 첨부하겠다
귀찮은거 아님
CLI> man 7 signal
그럼 이만
'BackEnd > Linux' 카테고리의 다른 글
Notepad로 UTF-8 BOM 문제 해결하기 (1) | 2024.09.03 |
---|---|
OpenSSL docs 정리 (업데이트 예정) (0) | 2021.06.25 |
ls 명령어/파일목록/linux ls (0) | 2021.06.17 |
심볼릭 링크(Symbolic Link) (2) | 2020.12.17 |