아래의 교재를 바탕으로 진행되는 ‘건국대학교 컴퓨터공학부’ 진현욱 교수님 수업을 바탕으로 정리된 내용입니다.
https://pages.cs.wisc.edu/~remzi/OSTEP/
Operating Systems: Three Easy Pieces
Blog: Why Textbooks Should Be Free Quick: Free Book Chapters - Hardcover - Softcover (Amazon) - Buy PDF - EU (Lulu) - Buy in India - Buy Stuff - Donate - For Teachers - Homework - Projects - News - Acknowledgements - Other Books Welcome to Operating System
pages.cs.wisc.edu

Program vs Process
- Program
- Bunch of instructions and static data in the disk
- CPU가 이해할 수 있는 명령어들이 포함되어 있음.
- executable file의 형태로 디스크에 다 저장되어 있음.
- Process
- A running program, 실행되고 있는 프로그램.
- Machine state
- Memory: instructions and data
- Registers: Program counter, stack pointer, etc.
- Others: list of the files the process currently has open
- APIs
- Create, destroy, wait, miscellaneous control, and status
- fork() System Call
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
printf("hello world (pid:%d)\n", (int) getpid());
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
printf("I am child (pid:%d)\n", (int) getpid());
} else {
printf("I am parent of %d (pid:%d)\n", rc, (int) getpid());
}
return 0;
}

- wait() System Call
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[]){
printf("hello world (pid:%d)\n", (int) getpid());
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
printf("I am child (pid:%d)\n", (int) getpid());
} else {
int wc = wait(NULL);
printf("I am parent of %d (wc:%d) (pid:%d)\n", rc, wc, (int) getpid());
}
return 0;
}

- 항상 child → parent 순서
- exec() System Call
- execvp?
- int execvp( const char file_path, *char** *const argv[])
- execvp?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char *argv[]){
printf("hello world (pid:%d)\n", (int) getpid());
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
printf("I am child (pid:%d)\n", (int) getpid());
char *myargs[3];
myargs[0] = strdup("fork");
myargs[1] = strdup("exec.c");
myargs[2] = NULL;
execvp(myargs[0], myargs);
printf("this shouldn’t print out\n");
} else {
int wc = wait(NULL);
printf("I am parent of %d (wc:%d) (pid:%d)\n", rc, wc, (int) getpid());
}
return 0;
}
Crux of the Problem
- 만약에 프로세스들이 엄청 많아지면 어떻게 될까?
- 가지고 있는 CPU, Core의 갯수는 한정적인데…
- 이보다 더 많은 프로세스를 실행시킬때 어떻게 작동하는가??
- 가지고 있는 CPU, Core의 갯수는 한정적인데…
- Virtualiation of the CPU
- Sharing a Toy
- 현실은 만만치 않다..
- 가장 대표적인 방법은 “Time Sharing”이다.
- 시간이 지나면 자원을 뺏어서 다른 프로세스에게 주는 개념
- Time Sharing을 한다고 하면 한정적인 CPU 자원에 대해서 여러 프로세스를 동시에 돌리는 것과 같은 Abstraction을 줄 수 있음.
- 사용자 입장에서는 CPU, Core 갯수에 제약을 받지 않고, 여러 프로세스들이 병렬적으로 실행되는 것처럼 보일 수 있음
- 모든 프로세스의 성능이 떨어지는 것 아닌가?
- Context Switch의 Overhead…
- 효율성..
- 어떤 관점에 따라서는 좋을 수도, 다른 관점에 따라선 나쁠 수도 있음.
- Sharing a Toy

프로세스의 상태
- Process State
- Running
- 현재 이 프로세스가 CPU자원을 할당받아서 실행되고 있는 상태
- Ready
- CPU자원이 할당되면 언제든지 실행될 수 있는데, 현재는 받지 못해서 기다리고 있는 상태
- Blocked(Waiting)
- 프로세스가 실행이 되다보면, CPU 자원을 할당받아서 실행하고 있었는데, 계속해서 실행을 하지 못하는 경우
- 프로세스가 I/O 요청을 한 경우, 일반적으로 CPU에 비해 속도가 느리기 때문에, 데이터를 요청했을 때 제공을 기다리는 시간동안 Blocked 상태로 옮겨주게 됨.
- wait 시스템 콜을 사용한 경우, 어느 프로세스가 끝날 때까지 기다리는 경우(계속 기다리는 경우)
- Running

- Example
Time | P0 | P1 | Notes |
1 | Running | Ready | |
2 | Running | Ready | |
3 | Running | Ready | P0 initiates I/O |
4 | Blocked | Running | P0 is blocked, so P1 runs |
5 | Blocked | Running | |
6 | Blocked | Running | |
7 | Ready | Running | I/O done |
8 | Ready | Running | P1 now done |
9 | Running | - | |
10 | Running | - | P0 now done |
- CPU0 하나만 있다고 가정했을 때, CPU자원을 할당받은 프로세스 순서(Time 순서)
0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
Data Structures (Process Control Blocks)
- 운영체제는 프로세스 하나가 생성될 때마다 해당 프로세스를 관리하기 위한 자료구조를 함께 생성한다
- 이를 Process Control Block이라고 한다 (PCB)
- 네트워크에서도 PCB 약자를 사용(Protocol Control Block), 이와 헷갈리지 말 것.
- Linux kernel
- /include/linux/sched.h
- task_struct 구조체가 PCB 역할을 해준다.
- Ready라는 State를 따로 구별하지 않음 → TASK_RUNNING 상태로 포함
- stack은 프로세스가 실행되면서 함수가 실행될 때마다 temporal한 정보를 넣기 위한 스택의 위치를 알려주는 포인터
- 프로세스마다 스택은, 유저쪽 코드를 실행하는 스택과 시스템 콜을 호출해서 커널안으로 진입했을 때 실행되는 코드를 위한 스택이 각각 존재. (각각 user-mode stack, kernel-mode stack)
- cpu는 현재 프로세스가 몇 번 cpu 코어에서 다뤄지는 지 정보를 담고 있음
- mm은 Memory_virtualization을 하기 위한 정보를 담고 있는 구조체
- parent, children은 fork에 의해서 생성된 관계 정보를 저장.
- 커널 안에서 circular_doubled_linked_list로 관리됨.
- files에서는 해당 프로세스에서 연 파일 정보를 담고 있음
struct task_struct {
volatile long state; // Running, Ready, Blocked 상태보다 훨씬 많은 state가 존재(세분화됨)
void *stack;
...
unsigned int cpu;
...
struct mm_struct *mm;
...
struct task_struct *parent;
struct list_head children;
...
struct files_struct *files;
...
}
Scheduling Queues
- OS manages three types of queue
- 각각의 CPU마다 상태별로 프로세스들을 구분해서 Queue에 넣어준다.
- Run queue
- Ready queue (레디~큐 🫨)
- Waiting queue
- 앞서 본 Example에서 프로세스들이 어떤 Queue에 넣어지는지 보자.
Time | P0 | P1 | Notes | Queue |
1 | Running | Ready | Run Queue -> P0 Ready Queue -> P1 Waiting Queue -> X |
|
2 | Running | Ready | ||
3 | Running | Ready | P0 initiates I/O | |
4 | Blocked | Running | P0 is blocked, so P1 runs | Run Queue -> P1 Ready Queue -> X Waiting Queue -> P0 |
5 | Blocked | Running | ||
6 | Blocked | Running | ||
7 | Ready | Running | I/O done | Run Queue -> P1 Ready Queue -> P0 Waiting Queue -> X |
8 | Ready | Running | P1 now done | |
9 | Running | - | ||
10 | Running | - | P0 now done |
참고
https://medium.com/@sohailk1999/five-state-process-model-6e83d7428c8c
'University > 운영체제' 카테고리의 다른 글
About Limited Direct Execution (2) | 2024.03.12 |
---|
아래의 교재를 바탕으로 진행되는 ‘건국대학교 컴퓨터공학부’ 진현욱 교수님 수업을 바탕으로 정리된 내용입니다.
https://pages.cs.wisc.edu/~remzi/OSTEP/
Operating Systems: Three Easy Pieces
Blog: Why Textbooks Should Be Free Quick: Free Book Chapters - Hardcover - Softcover (Amazon) - Buy PDF - EU (Lulu) - Buy in India - Buy Stuff - Donate - For Teachers - Homework - Projects - News - Acknowledgements - Other Books Welcome to Operating System
pages.cs.wisc.edu

Program vs Process
- Program
- Bunch of instructions and static data in the disk
- CPU가 이해할 수 있는 명령어들이 포함되어 있음.
- executable file의 형태로 디스크에 다 저장되어 있음.
- Process
- A running program, 실행되고 있는 프로그램.
- Machine state
- Memory: instructions and data
- Registers: Program counter, stack pointer, etc.
- Others: list of the files the process currently has open
- APIs
- Create, destroy, wait, miscellaneous control, and status
- fork() System Call
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
printf("hello world (pid:%d)\n", (int) getpid());
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
printf("I am child (pid:%d)\n", (int) getpid());
} else {
printf("I am parent of %d (pid:%d)\n", rc, (int) getpid());
}
return 0;
}

- wait() System Call
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[]){
printf("hello world (pid:%d)\n", (int) getpid());
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
printf("I am child (pid:%d)\n", (int) getpid());
} else {
int wc = wait(NULL);
printf("I am parent of %d (wc:%d) (pid:%d)\n", rc, wc, (int) getpid());
}
return 0;
}

- 항상 child → parent 순서
- exec() System Call
- execvp?
- int execvp( const char file_path, *char** *const argv[])
- execvp?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char *argv[]){
printf("hello world (pid:%d)\n", (int) getpid());
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
printf("I am child (pid:%d)\n", (int) getpid());
char *myargs[3];
myargs[0] = strdup("fork");
myargs[1] = strdup("exec.c");
myargs[2] = NULL;
execvp(myargs[0], myargs);
printf("this shouldn’t print out\n");
} else {
int wc = wait(NULL);
printf("I am parent of %d (wc:%d) (pid:%d)\n", rc, wc, (int) getpid());
}
return 0;
}
Crux of the Problem
- 만약에 프로세스들이 엄청 많아지면 어떻게 될까?
- 가지고 있는 CPU, Core의 갯수는 한정적인데…
- 이보다 더 많은 프로세스를 실행시킬때 어떻게 작동하는가??
- 가지고 있는 CPU, Core의 갯수는 한정적인데…
- Virtualiation of the CPU
- Sharing a Toy
- 현실은 만만치 않다..
- 가장 대표적인 방법은 “Time Sharing”이다.
- 시간이 지나면 자원을 뺏어서 다른 프로세스에게 주는 개념
- Time Sharing을 한다고 하면 한정적인 CPU 자원에 대해서 여러 프로세스를 동시에 돌리는 것과 같은 Abstraction을 줄 수 있음.
- 사용자 입장에서는 CPU, Core 갯수에 제약을 받지 않고, 여러 프로세스들이 병렬적으로 실행되는 것처럼 보일 수 있음
- 모든 프로세스의 성능이 떨어지는 것 아닌가?
- Context Switch의 Overhead…
- 효율성..
- 어떤 관점에 따라서는 좋을 수도, 다른 관점에 따라선 나쁠 수도 있음.
- Sharing a Toy

프로세스의 상태
- Process State
- Running
- 현재 이 프로세스가 CPU자원을 할당받아서 실행되고 있는 상태
- Ready
- CPU자원이 할당되면 언제든지 실행될 수 있는데, 현재는 받지 못해서 기다리고 있는 상태
- Blocked(Waiting)
- 프로세스가 실행이 되다보면, CPU 자원을 할당받아서 실행하고 있었는데, 계속해서 실행을 하지 못하는 경우
- 프로세스가 I/O 요청을 한 경우, 일반적으로 CPU에 비해 속도가 느리기 때문에, 데이터를 요청했을 때 제공을 기다리는 시간동안 Blocked 상태로 옮겨주게 됨.
- wait 시스템 콜을 사용한 경우, 어느 프로세스가 끝날 때까지 기다리는 경우(계속 기다리는 경우)
- Running

- Example
Time | P0 | P1 | Notes |
1 | Running | Ready | |
2 | Running | Ready | |
3 | Running | Ready | P0 initiates I/O |
4 | Blocked | Running | P0 is blocked, so P1 runs |
5 | Blocked | Running | |
6 | Blocked | Running | |
7 | Ready | Running | I/O done |
8 | Ready | Running | P1 now done |
9 | Running | - | |
10 | Running | - | P0 now done |
- CPU0 하나만 있다고 가정했을 때, CPU자원을 할당받은 프로세스 순서(Time 순서)
0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
Data Structures (Process Control Blocks)
- 운영체제는 프로세스 하나가 생성될 때마다 해당 프로세스를 관리하기 위한 자료구조를 함께 생성한다
- 이를 Process Control Block이라고 한다 (PCB)
- 네트워크에서도 PCB 약자를 사용(Protocol Control Block), 이와 헷갈리지 말 것.
- Linux kernel
- /include/linux/sched.h
- task_struct 구조체가 PCB 역할을 해준다.
- Ready라는 State를 따로 구별하지 않음 → TASK_RUNNING 상태로 포함
- stack은 프로세스가 실행되면서 함수가 실행될 때마다 temporal한 정보를 넣기 위한 스택의 위치를 알려주는 포인터
- 프로세스마다 스택은, 유저쪽 코드를 실행하는 스택과 시스템 콜을 호출해서 커널안으로 진입했을 때 실행되는 코드를 위한 스택이 각각 존재. (각각 user-mode stack, kernel-mode stack)
- cpu는 현재 프로세스가 몇 번 cpu 코어에서 다뤄지는 지 정보를 담고 있음
- mm은 Memory_virtualization을 하기 위한 정보를 담고 있는 구조체
- parent, children은 fork에 의해서 생성된 관계 정보를 저장.
- 커널 안에서 circular_doubled_linked_list로 관리됨.
- files에서는 해당 프로세스에서 연 파일 정보를 담고 있음
struct task_struct {
volatile long state; // Running, Ready, Blocked 상태보다 훨씬 많은 state가 존재(세분화됨)
void *stack;
...
unsigned int cpu;
...
struct mm_struct *mm;
...
struct task_struct *parent;
struct list_head children;
...
struct files_struct *files;
...
}
Scheduling Queues
- OS manages three types of queue
- 각각의 CPU마다 상태별로 프로세스들을 구분해서 Queue에 넣어준다.
- Run queue
- Ready queue (레디~큐 🫨)
- Waiting queue
- 앞서 본 Example에서 프로세스들이 어떤 Queue에 넣어지는지 보자.
Time | P0 | P1 | Notes | Queue |
1 | Running | Ready | Run Queue -> P0 Ready Queue -> P1 Waiting Queue -> X |
|
2 | Running | Ready | ||
3 | Running | Ready | P0 initiates I/O | |
4 | Blocked | Running | P0 is blocked, so P1 runs | Run Queue -> P1 Ready Queue -> X Waiting Queue -> P0 |
5 | Blocked | Running | ||
6 | Blocked | Running | ||
7 | Ready | Running | I/O done | Run Queue -> P1 Ready Queue -> P0 Waiting Queue -> X |
8 | Ready | Running | P1 now done | |
9 | Running | - | ||
10 | Running | - | P0 now done |
참고
https://medium.com/@sohailk1999/five-state-process-model-6e83d7428c8c
'University > 운영체제' 카테고리의 다른 글
About Limited Direct Execution (2) | 2024.03.12 |
---|