[Linux] Context Switching & Process State

정재훈·2022년 4월 11일
0

Linux

목록 보기
14/19

프로세스

init 프로세스 : 리눅스를 부팅하면 실행되는 최초의 프로세스로 시스템 프로세스에 필요한 여러 프로세스를 순차적으로 실행해준다. init 프로세스 PID는 1번이다.
PID : Process ID로 각 프로세스는 ID가 존재한다.

Fork System Call : 최초 프로세스를 제외한 모든 프로세스들은 부모 프로세스에서 복제되어 생성된다.
프로세스들은 부모 프로세스가 존재하며, 자식은 부모의 ID(PPID = Parent PID)값을 알고 있지만, 부모는 자식의 ID값을 모른다.

Shell에서 APP을 수행하면 Shell이 부모 프로세스가 된다.

PID 확인

findme.c

#include <stdio.h>
#include <unistd.h>

int main()
{
    while(1)
    {
        printf("#");
        setbuf(stdout,NULL);
        sleep(3);
    }
    return 0;
}

해당 코드를 통해 PID를 확인해보자. While문이 들어간 이유는 PID가 나타났다 사라지는걸 방지하기 위함이다.

PID 확인 방법

1. ps -ef
2. htop
3. top

주로 1번과 2번을 통해 확인한다.

ps-ef | grep findme : 계정명 옆에 나오는 2개가 PID와 PPID 순 = 39034/36349

htop : 맨 좌측에 표시된것이 PID, PPID는 따로 설정해줘야 보인다. = 39034

최초의 프로세스 PID

족보확인 : htop에서 F5 혹은 Pstree

htop 구성 및 설정

RES : 프로세스가 사용중인 실제 메모리 사이즈
VIRT : 프로세스가 사용중인 가상 메모리 사이즈
SHR : 프로세스가 사용중인 공유 메모리 사이즈

Tree view

F5를 통해 족보를 확인할 수 있다.

F9

F9을 통해 더욱 상세한 설정을 할 수 있다. PPID 확인도 가능케 설정변경 가능하다.

Process 구성

text/data/bss/stack/heap = 코드/초기화 전역/초기화 x 전역/ 지역/ malloc

실제 메모리 vs 가상 메모리

실제 메모리는 각 프로세스는 가상 메모리처럼 연속적인 메모리 공간을 사용하고 있지는 않다.

MMU : Memory Management Unit - 가상 주소를 DRAM의 실제 주소와 매핑 시키는 Address Translation(주소 변환) 역할을 수행합니다.
Shadowing : 프로그램 전체를 DRAM에 올림 - 시간이 많이 걸림, 임베디드 경우 메모리 부족
Demand Paging : 일부만 올림, 속도가 빨라라지지만 다 올린것이 아니라서 명령에 따른 주소를 이동하고자 할때 해당 주소가 없어 문제가 발생할 여지가 있다.

가상메모리 사용 이유

모든 프로세스는 메모리 Address를 0x0000 0000부터 사용가능하며, 타 메모리가 사용하는 공간도 마음껏 사용한다.
가상 메모리를 사용하기 위해서는 MMU가 필수적이다. 다중 Process에 MMU가 필수이며, MMU 없을시 Firmware나 RTOS로 개발한다.

가상 주소를 이용하여 실제 메모리에 접근하는 과정

프로세스 구성들의 메모리 주소 확인해보기

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int g1;
unsigned int g2 = 32;

int main()
{
    int l1 = 31;
    int *l2 = (int *)malloc(4);

    while(1)
    {
        printf("Address of function main is 0x%p\n", &main); // text 영역
        printf("data (%d) = %p\n",g2, &g2); // data 영역
        printf("bss (%p)\n" , &g1); // bss 영역
        printf("heap (%p)\n", l2); // heap 영역
        printf("stack (%p)\n", &11); // stack 영역

        sleep(5);
        printf("=================\n");
    }


    return 0;
}

결과

cat /proc/[PID]/maps

Context Switching

Single Core로 가정한다.
하나의 Core는 여러개 프로세스를 순환하면서 수행한다.
특정 시간마다 차례대로 수행한다. 대체로 Round Robin으로 동작하며 OS마다의 계산 공식에 의해 우선순위가 변경된다.

Context Switching : 우선순위에 따라 프로세스를 변경해야할 때 기존 프로세스의 진행 사항을 저장하고 복원한다.

참고) IPC : 프로세스 간 메모리를 공유하는 방법
PCB : Process Control Block - 커널이 프로세스를 제어하기 위한 정보를 저장하는 블록 - 프로세스 상태, PID, PC 등 프로세스에 대한 다양한 정보들을 보관

PC : Program Counter - 현재 진행하고 있는 진행상황에 대한 주소

프로세스 전환시 사용중이던 레지스터들을 PCB에 저장한다. 다음 Process로 전환 후, PCB에 저장된 레지스터를 Core로 가져온다.

결론) Context Switching 많아지면 동시에 수행하는 것처럼 보여 사용성이 좋아지지만, 레지스터 복원 복구 횟수가 증가하여 CPU가 부담이 커진다. 적절한 스케쥴링 정책이 필요하다.

Process State

Context Switching으로 선택된 하나의 프로세스만 수행 되는데, 수행중인 상태를 Running State라고 하고 나머지 프로세스들을 Runnable(Ready) 상태가 된다.

Uninterruptible Sleep(D) : 특정한 System Call 호출시 발생하는 State ex) mkdir - 응답이 올때까지 멈출 수 없는 잠을 잔다.

Inrerruptibble Sleep(S) : 어떤 동작을 기다리고 있을 때 / Sleep 사용시 진입하는 State , I/O 처리를 한 후, 응답이 오기 까지 대기한다. ex) Timer

Zombie(Z) : 자식이 죽고 난 후, 부모가 자식의 PCB를 제거해주기 전 상태, 자식이 죽게되면 SIGCHLD signal을 보내고 그 신호를 받은 부모가 PCB를 제거한다.

SISSTOP : crtl + Z으로도 가능

profile
여러 방향으로 접근하는 개발자

0개의 댓글