Linux

Linux 프로그램, 프로세스, 쓰레드

Bithub 2024. 3. 14. 10:58
728x90

프로그램

프로그램이란, HDD 또는 SSD에 저장된 실행가능한 바이너리 코드(0100011...)


프로세스

프로세스란?

프로그램이 RAM에 로드되어 있는 상태.

* 비유 : 프로세스 = 작업장 / 쓰레드 = 일꾼


multi-process = 프로세스가 여러개


새 프로세스 생성 시

  • Windows : 맨땅에서 process를 새로 만듬
  • Linux : fork() 함수를 사용하여 기존 process를 복제해서 만듬.

부모/자식 프로세스란?

 

부모 프로세스 : 복제를 수행한 프로세스

자식 프로세스 : 복제된 프로세스

자식 프로세스가 모종의 이유로 죽을 경우, Linux kernel은 부모 프로세스에게 자식 프로세스가 죽었다는 signal을 보낸다. 이 signal이 바로 '종료 코드(종료 상태)'다.


프로세스 아이디(PID)란?

프로세스를 구분하기 위해 프로세스에게 부여되는 고유 아이디. 0이상의 정수값을 가짐.

* PPID = 부모 프로세스의 PID

 

ps

  PID TTY          TIME CMD
   14 tty1     00:00:00 bash
   44 tty1     00:00:00 ps

명령어 ps를 수행하면 로그인한 사용자가 현재 실행되고 있는 프로세스의 목록을 볼 수 있다.

 

ps -ef

UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 10:40 ?        00:00:00 /init
root        13     1  0 10:40 tty1     00:00:00 /init
hello       14    13  0 10:40 tty1     00:00:00 -bash
hello       45    14  0 10:45 tty1     00:00:00 ps -ef

만약 다른 사용자가 실행하고 있는 프로세스의 목록을 확인하고 싶다면 ps -ef를 통해 Linux 시스템의 모든 프로세스 목록을 확인할 수 있다.

 

top

결과>
Tasks:   4 total,   1 running,   3 sleeping,   0 stopped,   0 zombie
%Cpu(s):  2.7 us,  1.4 sy,  0.0 ni, 95.8 id,  0.0 wa,  0.2 hi,  0.0 si,  0.0 st
KiB Mem : 67010176 total, 58838092 free,  7942732 used,   229352 buff/cache
KiB Swap:        0 total,        0 free,        0 used. 58933712 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0    8972    428    348 S   0.0  0.0   0:00.04 init
   13 root      20   0    9320    240    188 S   0.0  0.0   0:00.00 init
   14 hello     20   0   16804   3480   3384 S   0.0  0.0   0:00.04 bash
   42 hello     20   0   17632   2092   1556 R   0.0  0.0   0:00.02 top

프로세스의 목록과 각 프로세스 별로 CPU와 메모리 사용량을 볼 수 있다.

사용량은 자동으로 3초에 한번씩 갱신된다.

Enter : 수동으로 사용량 갱신

q : 종료


프로세스 간 통신 : 시그널

프로세스 간 통신에는 크게 2가지 방법이 있다 : 1) pipe, 2) signal

시그널은 어떤 프로세스에게 특정 사건이 발생하였음을 알리는 메커니즘이다.

만약 어떤 프로세스가 시그널을 받고 아무 동작도 취하지 않는다면, 디폴트로 프로세스는 종료된다.


시그널의 종류

kill -l 명렁어를 통해 시그널의 종류를 확인할 수 있다.

kill -l

 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

 

총 64번까지 있는데 34번부터는 realtime signal이다.

우리가 명렁어를 종료할 때 자주 사용하는 ctrl + C를 누르는 행위도 시그널을 보내는 것이다.

 

그럼 어떤 시그널을 보내는 것일까? stty -a를 통해 확인이 가능하다.

stty -a

speed 38400 baud; rows 30; columns 120; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = M-^?; start = ^Q; stop = ^S;
susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc ixany imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc

 

CTRL + C는 interrupt(SIGINT(2)) 시그널을 보내고 CTRL + D는 EOF를 보내는 것을 확인할 수 있다.

다만, 주의할점이 프로세스에 따라 SIGINT 시그널을 받아도 종료되지 않을 수 있다.

프로세스가 수신된 시그널에 따른 동작이 정의되어 있다면, 종료되지 않을 것이다.


시그널 SIGKILL(9)

그 어떠한 Linux 프로그램도 SIGKILL 시그널에 따른 동작을 정의하지 못한다.

즉, SIGKILL 시그널을 보내면 프로그램은 반드시 죽는다.


 

 

시그널 전송방법

kill은 시그널을 보내는 명령어다.

kill -signal number pid 또는 kill -signal name pid를 이용해서 시그널 전송 가능.

# SIGINT(2) 전송
kill -2 311
kill -int 311

# SIGKILL(9) 전송
kill -kill 300
kill -9 300

종료 코드

'종료 코드'는 자식 프로세스가 종료된 이유를 부모 프로세스에게 알리기 위한 용도로 사용된다.

0~255의 값을 가지며, 0인 경우 정상적으로 종료되었음, 0이 아닌 경우 비정상적으로 종료되었음을 나타낸다.

 

어떤 프로세스가 시그널에 의하여 종료된 경우,

종료코드 = 128 + 시그널 번호

 

예를 들어, SIGINT(2)를 받아 종료되었다면 종료코드는 130이 된다.

 

echo $?를 통해 종료코드를 확인할 수 있다.

echo $?

 

+번외.

echo $!

 

마지막 명령어로 실행된 명령어의 PID 값을 출력

echo $$

 

현재 쉘의 PID값을 출력