반응형

프로세스 이해와 생성

3.1 Process Concept

실행중인 프로그램을 프로세스라고 한다. (메모리에 올라옴)
OS의 작업의 단위는 프로세스다

Process는 아래 자원(resources)을 필요로 한다.

  • CPU time
  • memory
  • files
  • I/O devices

프로세스의 메모리 레이아웃

프로세스의 메모리 레이아웃

  • Text section : 명령어 나열
  • Data section : 전역변수들
    • initialized data
    • uninitalized data
  • Heap section : 동적으로 메모리 사용 (memory that is dynamically allocated during program run time)
  • Stack section : 함수 호출
    • temporary data storage when invoking functions
    • such as function parameters, return addresses, and local variables

프로세스의 생명주기

프로세스 생명주기

  • New : 프로세스가 막 생성된/중인 상태. fork()
  • Ready : CPU 점유할 준비가 다 되었을 때의 상태. I/O나 event가 끝났다고 바로 CPU를 할당받지 않음. ready queue에 들어감
  • Running : 프로세스가 CPU를 점유하여 쓰기 시작함. CPU 스케쥴링에 의해 CPU 획득 시의 상태
  • Waiting : 잠시 멈춤 (ex: 시분할로 다른 프로세스가 CPU 사용, I/O(키보드 등)나 이벤트가 발생되었을 때 잠시 대기한다던가ㅇㅇ!). waiting queue에 들어감
  • Terminated : 프로세스 종료

PCB (Process Control Block) (=TCB (Task Control Block)) 혹은 Context(문맥)

  • 각 프로세스가 가져야하는 모든 정보를 PCB에 저장하자
  • Process state (프로세스 생명주기)
  • Context
    • Program counter (PC) : 실행중은 프로세스의 명령어를 어디까지 실행했는지 저장함. 명령어 레지스터(IR)가 PC에 갖고 있는 주소에 해당하는 메모리를 fetch하여 명령어를 가져옴)
    • CPU registers (IR, DR, …)
  • CPU-scheduling information : CPU를 주고받거나 릴리즈하기 위해 필요한 정보
  • Memory-management information
  • Accounting information : 프로세스의 소유자 등
  • I/O Status information : 어떤 자원을 오픈하고 락을 걸어놨는지 등

실행 실타래(a single thread of execution)

  • 프로세스는 싱글스레드! 하나의 실타래! (a program that performs a single thread of execution.) → 여기서 말하는 싱글스레드는 하나의 실행 흐름을 말하는 것으로, 프로세스 내의 스레드와 의미가 다름
  • 싱글 스레드는 한번에 하나의 작업밖에 가능하지 않다.
  • 멀티 테스킹과 멀티프로세싱을 제공해주는 게 OS의 핵심 업무임 (multiple threads of execution)

스레드 (thread, 실행실타래 개념에서 착안하여 만든 경량화된 프로세스)

  • OS가 PCB를 이용하여 시분할을 하듯이, 하나의 프로세스 안에서도 여러개로 쪼개면 되지 않을까?
  • 저렴하고 여러모로 장점이 많기 때문에 멀티 프로세싱(프로세서) 보다는 멀티 스레딩 위주로 사용함

3.2 Process Scheduling

    • 목적 : 멀티 프로그래밍, 멀티 테스킹을 통해 여러 개의 프로세스를 동시에 실행시켜서 CPU 사용 효율을 극대화하자
    • 구현을 위한 개념
      • 동시성 : concurrently, at the same time, simultaneously
      • 병렬성 : parallelly
    • Time sharing (시분할)의 목적 : 프로세스간에 자주 스위칭하여 사용자가 각 프로그램이 동시에 돌고 있는 것 처럼 보이게 하기 위함
    • 시분할 하기 위해 Scheduling Queues가 필요함. 아래 큐는 PCB 들을 linked list로 연결하여 구현할 수 있음
      • ready queue : 대기열에서 CPU 할당을 받기 위해 프로세스가 대기하는 공간. 맨 위 1개가 레디큐
      • waiting queue : I/O, event가 발생한 동안 대기하는 공간. 두번째부터 웨이팅큐들

    • Queue Diagram
      • Ready queue에 있던 프로세스가 CPU를 할당받아 작업을 수행하다가 I/O Request, interrupt, for a child 등의 이벤트가 발생하면 다시 대기 상태(ready queue로 이동)로 변경된다. 혹은 시분할 받은 시간이 만료된 경우에도 대기상태로 변경된다.

    • Context switch : 문맥을 교환하는 작업도 OS가 처리해야함
      • PCB는 프로세스의 문맥(context)을 설명함 (OS 입장에서 문맥교환은 PCB 스위칭을 의미함)
      • interrupt가 발생한다면 OS는 실행중인 프로세스에 대한 문맥(PCB) PC에 저장해두고, 다시 해당 프로세스가 재개되었을때(Ready queue에 있다가 CPU를 다시 할당받았을때) 저장해놓았던 문맥(PCB)를 다시 restore함
      • 문맥 교환 작업은 현재 프로세스의 상태를 저장하고 새로운 프로세스의 상태를 보관(restore)하는 것

3.3 Operations on Processes

  • 멀티프로세싱(프로세서)는 OS Scheduler를 통해 문맥교환으로 이루어짐
  • 프로세스는 프로세스들을 만들 수 있음
    • 프로세스를 만드는 프로세스 : a prarent process
    • 부모 프로세스에 의해 만들어진 프로세스 : a child process
  • 프로세는 unix fork() 명령어로 생성 가능하며, 생성된 프로세스는 트리 구조를 가짐
  • 프로세스 실행
    1. The parent continues to execute concurrently with its children - 비동기 느낌. 부모와 자식 프로세스가 동시에 실행되는 거 처럼 동작
    2. The parent waits until some or all of its children have terminated - 동기 느낌. 자식 프로세스가 종료되기까지 부모가 기다림
  • address-space(주소공간)의 관리
    1. The child process is a duplicate of the parent process : 만약 동일한 작업을 하는 프로세스라면(실행하는 컨텍스트가 똑같다면) 별도의 P1, P2 공간을 만들지 않고 PCB만 추가
    2. The child process has a new program loaded into it
  • A process terminate
    • 마지막 문장 실행
    • exit() system call : asks OS to delete it
      • OS는 관련된 자원의 메모리 해제(deallocates) 및 해소(reclaims) : allocated되었던 memories, open files, and I/O buffers 등
  • Zombie와 Orphan : 주로 데몬, 백그라운드 프로세스 만들 때 활용됨
    • 좀비 프로세스 : 자식 프로세스가 종료되었는데 부모가 wait()을 호출하지 않음
    • 고아 프로세스 : 부모 프로세스가 없는 자식 프로세스
  • fork() 라는 system call을 이용하여 새로운 프로세스를 생성함
    • 새롭게 생성된 child process는 parent process의 address space를 복사한 공간을 가짐
    • 두 프로세스는 fork() 이후 지속적으로 실행됨
    • fork()로 실행된 자식 프로세스의 return code는 항상 0 이고, 자식 프로세스의 0이 아닌 pid는 부모 프로세스에게 리턴됨 (⇒ 자식 프로세스 PID는 0, 부모 프로세스는 1 이상)
    • fork()가 호출된 이후 부모 프로세스는 자식 프로세스와 동시에 실행될 수 있고 또는 대기하는 경우 부모 프로세스는 wait()을 호출하여 waiting queue에 들어가서 자식 프로세스가 실행되는 걸 기다릴 수 있음(자식 프로세스가 종료되어 interuppt를 걸어주기를 기다림)
  • exec()

3.3 실습

연습문제 3.1 전역변수 value 값은?

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

// 연습문제 3.1 value 값은 얼마일까? 5
int value = 5;
int main()
{
    pid_t pid;
    pid = fork();
    
    if (pid == 0) {
        value += 15;
        return 0;
    }
    else if (pid > 0) {
        wait(NULL);
        printf("Parent: value=%d\n", value); // line A
    }
    return 0;
}

연습문제 3.2 생성된 프로세스의 수는?

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

// 연습문제 3.2 몇개의 프로세스가 생성될까?
/*
2^4, 16개의 프로세스가 생성되었음!
*/
int main()
{
    fork();
    fork();
    fork();
    fork();
    printf("hello\n"); // 16번 수행되는 친구친구
    return 0;
}

 

연습문제 3.11 생성된 프로세스의 수는? 왜 기대한 프로세스의 수와 다를까? 🤨

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

// 연습문제 3.11
int main()
{
    int i;
    pid_t pid;
    for (i = 0; i < 4; i++) { //만약 for문에서 i 선언하면 결과 달라짐
        pid = fork();
        printf("hello, Linux %d\n", pid);
    }
    return 0;

/*
몇 개의 프로세스가 생길까?
16개의 프로세스가 생성되기를 기대했는데 왜 30개가 생기는걸까
-> 출력구문이 for문 내에 있어서 그렇다. 실제로는 2^n 만큼의 스레드만 생긴다
*/
}

연습문제 3.12 execlp

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

// 연습문제 3.12
/*
자시자신을 복제(fork)하는 게 아니라 새로운 작업을 별도 스레드로 실행시키고 싶을 때 execlp 를 활용함.
이때 새롭게 생성된 P1의 공간을 execlp로 뒤덮는 것이기 때문에 이후 명령어(ex: printf)는 씹히게 된다.
*/
int main() {
    pid_t pid;
    pid = fork();
    if (pid == 0) { // child process 
        execlp("/bin/ls", "ls", NULL); printf("LINE J\n");
    }
    else if (pid > 0) { // parent process
        wait(NULL);
        printf("Child Complete\n");
    }
return 0; 
}

연습문제 3.13

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

// 연습문제 3.13
// child pid1는 자기자신의 pid이기 때문에, parent 프로세스의 pid 변수와 동일해야함
/*
parent : pid = 64351
parent : myPid = 64350
child : pid = 0
child : myPid = 64351
*/
int main()
{
    pid_t pid, myPid;
    pid = fork();
    if (pid > 0) {//parent process
        myPid = getpid();
        printf("parent : pid = %d\n", pid); // child pid
        printf("parent : myPid = %d\n", myPid); // 자기자신의 pid (부모 pid)
        wait(NULL);
    }
    else if (pid == 0) {
        myPid = getpid();
        printf("child : pid = %d\n", pid); // 
        printf("child : myPid = %d\n", myPid); // 자시자신의 pid
    }
    return 0;
}

 

퀴즈 2-6 풀이

wait() 타기 전에 컨텍스트 스위칭이 일어나면? 동기화 문제가 발생함! 이거에 대해서도 쭉 공부할것임

반응형