Linux

[바미] 프로세스와 커널에 대해 알아보자!

Bami 2021. 1. 18. 15:06
728x90
반응형

프로세스와 커널

프로세스(Process)는 운영체제의 커널의 관리하에 현재 시스템에서 동작중인 프로그램, 실행 중인 프로그램의 인스턴스 인데 시스템 리소스(예: CPU, 메모리, 파일 등)를 할당받아 작업을 수행합니다.

 

커널은 프로세스를 관리하기 위해 각 프로세스에게 PCB를 할당하고, init프로세스는 부팅 시 가장 먼저 실행되어 시스템에 설정을 하는 초기화 프로세스 입니다.


프로세스 종류

프로세스에도 종류가 있는데 아래의 표와 같습니다.

프로세스명 설명
데몬 프로스세스 사용자에게 특정기능이나 서비스를 제공하는 프로그램입니다.
부모 프로세스 부모 프로세스는 다른 프로세스를 생성하며 init을 제외한 모든 프로세스는 부모 프로세스를 가지고 있습니다.
고아 프로세스 자식 프로세스보다 부모 프로세스가 먼저 종료가 되었을 때 자식프로세스는 고아 프로세스가 되어 init 프로세스가 관리하게 됩니다.
좀비 프로세스 자식 프로세스의 종료 신호를 부모 프로세스가 처리하지 못할 경우 자식 프로세스는 좀비 프로세스가 됩니다.

프로세스의 주요 구성 요소

 

  • 프로그램 코드 (Code)
    • 프로세스가 실행할 명령어 집합.
  • 데이터 (Data)
    • 전역 변수, 정적 변수 등.
  • 힙 (Heap)
    • 동적 메모리 할당 영역.
  • 스택 (Stack)
    • 함수 호출 시 사용되는 지역 변수 및 매개변수.
  • 프로세스 제어 블록 (PCB)
    • 프로세스의 상태, 프로그램 카운터, CPU 레지스터, 메모리 관리 정보 등을 포함한 데이터 구조.

프로세스와 커널 간의 상호작용

  1. 시스템 콜 (System Call)
    • 사용자 모드에서 실행 중인 프로세스가 커널 모드로 전환하여 커널 기능을 요청하는 메커니즘.
    • 예: 파일 열기, 메모리 할당, 프로세스 생성 등.
  2. 인터럽트 (Interrupt)
    • 하드웨어 또는 소프트웨어 이벤트가 발생하면, CPU는 현재 작업을 중단하고 커널의 인터럽트 핸들러를 실행합니다.
  3. 컨텍스트 스위칭 (Context Switching)
    • 커널은 하나의 프로세스 상태를 저장하고, 다른 프로세스 상태를 복원하여 CPU를 다른 프로세스로 전환합니다.

 

프로세스 확인하기

시스템에서 실행 중인 프로세스를 확인하기 위해 ps 명령어를 사용할 수 있습니다. ps 명령어는 현재 시스템에서 동작 중인 프로세스를 확인하는 데 사용됩니다.

ps 명령어의 사용법

ps 명령어는 다양한 옵션을 제공하여 프로세스 정보를 출력할 수 있는데 주요 옵션은 다음과 같습니다.

  • -e: 모든 프로세스에 대한 리스트를 출력합니다.
  • -f: 풀 포맷(full format)으로 출력합니다.
  • -a: 다른 사용자들의 프로세스도 출력합니다.
  • -u: 사용자 이름과 시간 등 상세한 정보를 출력합니다.
  • -x: 현재 실행되고 있는 모든 프로세스를 출력합니다.

보통 -e와 -f 옵션을 함께 사용하여 모든 프로세스를 풀 포맷으로 출력합니다.

예제

ps -ef

이 명령어를 입력하면 아래 스크린샷처럼 시스템에서 실행 중인 모든 프로세스가 풀 포맷으로 출력됩니다.

ps 명령어 사용 화면

ps -ef 명령어의 출력 필드 설명

ps -ef 명령어를 입력하면 아래와 같이 여러 필드가 포함된 출력이 나타나는데 각 필드의 의미는 다음과 같습니다.

UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 10:37 ?        00:00:01 init
root       234     1  0 10:37 ?        00:00:00 kthreadd
root       240     2  0 10:37 ?        00:00:00 kworker/0:1H
user      1300  1200  1 10:42 pts/0    00:00:00 bash
user      1345  1300  0 10:43 pts/0    00:00:00 ps -ef
  • UID: 프로세스를 실행시킨 소유자의 사용자 ID입니다.
  • PID: 프로세스 ID로, 실행된 프로세스에 부여된 고유 번호입니다.
  • PPID: 부모 프로세스 ID로, 해당 프로세스를 생성한 부모 프로세스의 PID를 나타냅니다.
  • C: 짧은 기간 동안의 CPU 사용률을 나타내는 스케줄링 관련 필드입니다.
  • STIME: 프로세스가 시작된 시간입니다.
  • TTY: 프로세스가 연결된 터미널을 나타냅니다.
  • TIME: 프로세스가 사용한 총 CPU 시간을 나타냅니다.
  • CMD: 실행된 프로세스의 이름 또는 실행한 명령입니다.

프로세스 다루기

프로세스에 대해 알아보았다면, 이제 프로세스를 다루는 방법 중 하나인 kill 명령어에 대해 설명하겠습니다.

kill 명령어

kill 명령어는 프로세스에게 SIGNAL(신호)을 전달하는 명령어입니다. 이를 통해 프로세스를 제어하거나 종료할 수 있습니다.

신호의 종류 확인

kill -l 명령어를 사용하여 kill 명령어로 보낼 수 있는 신호의 종류를 확인할 수 있습니다.

kill -l

kill 명령어의 사용 방법

kill -[번호/SIGNAL] [PID/작업번호]
  • 번호/SIGNAL: 보낼 신호의 번호 또는 이름
  • PID/작업번호: 프로세스 ID 또는 작업 번호

자주 사용하는 신호

  • 2번 SIGINT: 인터럽트 신호로, 주로 프로그램을 종료할 때 사용됩니다. (Ctrl+C)
  • 9번 SIGKILL: 강제 종료 신호로, 즉시 프로세스를 종료합니다.
  • 15번 SIGTERM: 종료 요청 신호로, 프로그램이 종료될 수 있도록 요청합니다.
  • 18번 SIGCONT: 정지된 프로세스를 재개합니다.
  • 19번 SIGSTOP: 프로세스를 일시 정지합니다.

예제

예를 들어, PID 100번의 프로세스를 종료하고 싶다면 다음과 같이 사용할 수 있습니다.

kill -9 100

또는

kill -SIGKILL 100

sleep 명령어

sleep 명령어는 입력한 시간 동안 대기 상태에 있는 프로세스를 생성하는 명령어입니다. 

주로 스크립트에서 특정 시간 동안 대기하도록 할 때 사용됩니다.

sleep [시간]

[시간] 부분에 대기할 시간(초 단위). 예를 들어, 5초 동안 대기하려면 sleep 5를 사용합니다.

 

예제

sleep 5

위 명령어는 5초 동안 대기하는 프로세스를 생성합니다.


프로세스의 동작형태

이제 프로세스를 다룰 수 있다면 프로세스의 동작형태에 대해 알아보겠습니다.

포어그라운드 프로세스 (Foreground Process)

  • 포어그라운드 프로세스는 CLI(Command Line Interface) 환경에서 대부분의 명령어가 실행되는 방식입니다.
  • 이러한 프로세스는 사용자와 직접 상호작용하며, 명령어의 실행 과정이나 결과를 화면에 출력합니다.
  • 예를 들어, 터미널에서 ls 명령어를 입력하면, 해당 명령어가 포어그라운드 프로세스로 실행되어 디렉토리 목록이 화면에 출력됩니다.

백그라운드 프로세스 (Background Process)

  • 백그라운드 프로세스는 프로세스가 종료되지 않은 상태에서도 즉시 명령 대기 상태로 돌아갈 수 있게 합니다. 즉, 다른 명령어를 사용하면서 동시에 실행될 수 있습니다.
  • 백그라운드로 실행하기 위해서는 명령어 마지막에 &(Ampersand)를 붙여 사용합니다.
  • 백그라운드는 주로 장시간 실행되는 작업에 사용됩니다.
  • cp -r /usr/gsk/sr1 & 명령어를 사용하면 [1] 5020이라는 출력이 나타납니다.

백그라운드 프로세스 관리

jobs 명령어

현재 백그라운드에서 실행 중인 프로세스를 확인할 수 있습니다.

jobs

fg 명령어

백그라운드 작업을 포어그라운드로 전환할 때 사용합니다.

fg %[작업번호]

bg 명령어

포어그라운드 작업을 백그라운드로 전환할 때 사용합니다.

bg %[작업번호]

 

시스템 프로세스 확인

시스템에서 실행되고 있는 프로세스는 /proc 디렉토리 아래에서 확인할 수 있습니다. 

/proc 디렉토리는 실제 하드디스크에 존재하지 않으며, 메모리에 저장된 내용을 확인할 수 있는 가상 디렉토리입니다.

메모리 정보 확인

cat /proc/meminfo

CPU 정보 확인

cat /proc/cpuinfo

커널 버전 확인

cat /proc/version

사용 하는 방법(Go)

Go 프로그램을 리눅스 환경에서 실행하기 위해 먼저 컴파일 해야 합니다 예를 들어서 myprogram.go라는 파일이 있다 가정하여 다음 명령어를 사용합니다.

go build -o myprogram myprogram.go

이제 myprogram이라는 실행 파일이 생성되었습니다.

 

그 후엔 생성된 실행 파일에 실행 권한을 부여해야 합니다.

chmod +x myprogram

 

이제 백그라운드에서 프로그램을 실행해보겠습니다.

./myprogram &

이렇게 하면 백그라운드로 실행시킬 수 있지만 터미널을 종료할 때 프로그램도 함께 종료됩니다.

nohup

그래서 터미널을 종료해도 프로그램이 계속 실행되도록 하기 위해 nohup을 사용해야 합니다.

nohup ./myprogram &

이렇게 하면 프로그램이 종료되는 시그널을 무시하게 하여, 터미널을 닫아도 프로그램이 계속 실행되게 합니다.

쉘 스크립트를 사용하는 방법

#!/bin/bash

# Go 프로그램 컴파일
go build -o myprogram myprogram.go

# 실행 파일에 실행 권한 부여
chmod +x myprogram

# nohup을 사용하여 백그라운드에서 실행
nohup ./myprogram &

echo "프로그램이 백그라운드에서 실행 중입니다. 로그는 nohup.out 파일에서 확인할 수 있습니다."

쉘 스크립트란?

쉘 스크립트는 쉘(명령어 해석기)에서 실행할 수 있는 명령어들을 모아 놓은 파일입니다. 이를 통해 여러 명령어를 자동으로 순차적으로 실행할 수 있습니다. 


그 외

systemd 서비스로 SleepService 만들기

systemd 를 이용해서 서비스로 만들기 위해서는 “/lib/systemd/system/sleepservice.service” 아래에

다음과 같은 것을 만든다.

[Unit] 
Description=Sleep service 
ConditionPathExists=/home/ubuntu/work/src/sleepservice/sleepservice 
After=network.target 

[Service] 
Type=simple 
User=sleepservice
Group=sleepservice 
LimitNOFILE=1024 
Restart=on-failure 
RestartSec=10 
startLimitIntervalSec=60 
WorkingDirectory=/home/ubuntu/work/src/sleepservice 
ExecStart=/home/ubuntu/work/src/sleepservice/sleepservice --name=foo 

# make sure log directory exists and owned by syslog 
PermissionsStartOnly=true 
ExecStartPre=/bin/mkdir -p /var/log/sleepservice
ExecStartPre=/bin/chown syslog:adm /var/log/sleepservice 
ExecStartPre=/bin/chmod 755 /var/log/sleepservice 
StandardOutput=syslog 
StandardError=syslog 
SyslogIdentifier=sleepservice 

[Install] 
WantedBy=multi-user.target

위의 파일에서 사용된 패스들은 여러분의 경로에 맞게 수정 하면 될 것 이다.

물론 sleepservice 라는 서비스 이름 자체도 말이다.

해당 프로그램 전용 사용자를 만들고 , 깃헙에서 만들어 둔것이 있으면 제대로 된 위치로 옮기고, 755 권한을 준다.

$ cd /tmp 
$ sudo useradd sleepservice -s /sbin/nologin -M 
$ wget https://raw.githubusercontent.com/fabianlee/blogcode/master/golang/sleepservice/systemd/sleepservice.service 
$ sudo mv sleepservice.service /lib/systemd/system/. 
$ sudo chmod 755 /lib/systemd/system/sleepservice.service

systemctl 를 이용해서 sleepservice.service 를 enable 시키고 시작시키고, journalctl 을 통해 제대로 시작되는지 확인한다.

$ sudo systemctl enable sleepservice.service

$ sudo systemctl start sleepservice

$ sudo journalctl -f -u sleepservice

May 21 16:20:43 xenial1 sleepservice[4037]: 2017/05/21 16:20:43 hello foo
May 21 16:20:43 xenial1 sleepservice[4037]: 2017/05/21 16:20:43 About to sleep 1526ms before looping again
May 21 16:20:45 xenial1 sleepservice[4037]: 2017/05/21 16:20:45 hello foo
May 21 16:20:45 xenial1 sleepservice[4037]: 2017/05/21 16:20:45 About to sleep 196ms before looping again

그 밖에도 기존의 etc/init.d 를 이용해서 할 수도 있다.

1) /etc/init.d 아래 스크립트 작성 (Golang 프로그램을 시작시키거나 멈추는 run 스크립트를 부팅시 호출 해준다.)

#! /bin/sh
# /etc/init.d/myservice


USERNAME=who??
COMMAND_MYSERVICE_SCRIPT="/home/$USERNAME/myservice/run"


case "$1" in
  start)
    echo "Starting myservice .."
    sudo -u $USERNAME $COMMAND_MYSERVICE_SCRIPTstart

    echo "Done!!"
    ;;
  stop)
    echo "Stopping myservice .."
    sudo -u $USERNAME $COMMAND_MYSERVICE_SCRIPTstop
    echo "Done!!"
    ;;
  *)
    echo "Usage: /etc/init.d/myservice {start|stop}"
    exit 1
    ;;
esac

exit 0

권한설정

  • sudo chmod 755 myservice
  • update-rc.d 로 설정 ( sudo update-rc.d myservice defaults)
728x90
반응형