그림으로 쉽게 배우는 운영체제 - 인프런 | 강의
이 강의를 통해 모든 개발자들이 필수로 알아야하는 운영체제의 원리를 알 수 있습니다., - 강의 소개 | 인프런...
www.inflearn.com
본 포스팅은 위 링크의 강의를 요약/정리한 것으로, 지식의 공유보다는 개인적으로 공부하고 복습하기 위해 기록한 것입니다.
프로그램과 프로세스
프로그램
🔗저장장치에 저장된 명령문의 집합체. 애플리케이션 혹은 앱이라 불린다(윈도우즈 운영체제의 .exe 파일)
프로세스
🔗저장장치에 저장된 프로그램이 메모리에 올라간 상태(간단히 말하면 실행 중인 프로그램)
🔗운영체제의 CPU 스케줄링 알고리즘에 따라 CPU를 사용하며 필요에 따라 입력과 출력을 한다
🔗프로세스의 구조
- 코드 영역: 프로그램을 실행하는 코드가 저장돼 있다
- 데이터 영역: 전역 변수와 스태틱 변수가 저장돼 있다
- 스택 영역: 지역 변수와 함수를 호출했을 때 필요한 정보가 저장된다(매개변수와 돌아갈 주소를 저장)
- 힙 영역: 프로그래머가 동적으로 메모리를 할당하는 데에 쓰인다(런타임이 할당할 수 있는 메모리 공간). C언어에서는 malloc() 함수와 free() 함수를 호출해서 힙 영역에 자원을 할당하거나 할당을 해제할 수 있다.
🔗C언어는 컴파일 언어이기 때문에 반드시 컴파일 과정을 거쳐야만 코드를 실행할 수 있다
C언어에서 코드가 프로세스가 되는 과정
🔗(두 숫자를 더하는 코드를 실행한다고 했을 때)전처리기에서 매크로로 정의한 숫자를 치환하고 필요한 파일을 불러온다.
- 전처리기: 프로그램의 조건에 맞추기 위한 사전 처리나 사전 준비적인 계산 또는 편성을 행하는 프로그램
🔗컴파일러가 고급 언어인 C언어를 저급 언어인 어셈블리어로 바꿔준다.
🔗어셈블러가 어셈블리어를 기계어로 바꿔준다.
🔗마지막으로 링커가 여러 라이브러리나 다른 소스코드들을 연결한다.(링킹)
🔗이 과정을 거치면 파일의 확장자는 .exe가 되며, .exe 파일이 실행되어 메모리에 올라가면 프로세스가 된다.
- 링커: 두 개 이상의 목적 프로그램을 합쳐서 실행 가능한 한 개의 프로그램으로 만드는 작업을 하는 프로그램
프로세스가 실행되는 과정
🔗CPU 내 제어장치가 계산할 숫자를 메모리에 저장한다.
🔗그 후 메모리에 저장된 값을 edx, eax 레지스터로 가져온다.
🔗제어장치가 레지스터에 저장된 숫자를 계산하라고 명령한다.
🔗산술논리 연산장치가 저장된 숫자를 계산하고 그 결과를 eax 레지스터에 저장한다.
🔗마지막으로 제어장치가 eax 레지스터에 저장된 결과값을 메모리에 저장한다.
멀티프로그래밍과 멀티프로세싱
멀티프로그래밍
🔗메모리 관점에서의 정의
🔗메모리에 여러 개의 프로세스가 올라온 것
- 반대로 오직 하나의 프로세스만 메모리에 올리는 것을 유니프로그래밍이라고 한다. 과거에는 메모리의 크기가 작아서 유니프로그래밍을 하면서 멀티프로세싱을 이용했다.
- 유니프로그래밍 환경에서의 멀티프로세싱
- 메모리에 프로세스를 올려서 CPU로 처리한 후 다른 저장장치에 저장한다.
- 다른 저장장치에 있던 프로세스를 메모리에 올려서 CPU로 처리한다.
멀티프로세싱
🔗CPU 관점에서의 정의
🔗CPU가 여러 개의 프로세스를 처리하는 것
🔗CPU가 시분할 처리로 각각의 프로세스를 짧은 시간 동안 교대로 실행
PCB
PCB
🔗Process Control Block의 약자
🔗프로세스가 만들어지면 운영체제는 해당 프로세스의 정보를 가진 PCB를 연결리스트로 생성해 저장한다.
🔗운영체제는 프로세스가 종료되면 연결리스트에서 해당 프로세스의 PCB를 제거한다.
🔗PCB의 구조
- 포인터
- 부모와 자식 프로세스에 대한 포인터, 할당된 자원에 대한 포인터, 프로세스의 상태를 저장하는 포인터 등
- 효율적인 접은을 위해 사용한다
- 프로세스 상태
- 현재 프로세스의 다섯 가지 상태(생성, 준비, 실행, 대기, 완료)를 나타낸다.
- 프로세스 ID
- 프로세스를 식별하기 위한 숫자를 저장
- 프로그램 카운터
- 다음에 실행될 명령어의 주소를 포함
- 시분할 처리 과정에서 프로세스가 실행을 멈췄다가 다시 실행될 때 이어서 작업할 수 있게 한다.
- 레지스터 정보
- 프로세스가 실행될 때 사용한 레지스터 값을 저장한다. 프로그램 카운터와 마찬가지로 이전 작업을 이어서 할 수 있게 한다.
- 메모리 관련 정보
- 프로세스의 메모리상 위치 정보, 메모리 침범을 막기 위한 경계 레지스터 값 등을 저장
- CPU 스케줄링 정보
- CPU 스케줄링에 필요한 우선 순위, 최종 실행 시간, CPU 점유 시간 등을 저장
프로세스 상태
프로세스의 상태
🔗프로세스에는 시분할 처리를 위한 다섯 가지 상태가 있다
🔗생성
- PCB를 생성하고 메모리에 프로그램 적재를 요청한 상태
- 적재를 승인받은 후 준비 상태로 이동
🔗준비
- CPU를 사용하기 위해 기다리는 상태
- 준비 상태의 프로세스는 CPU 스케줄러에 의해 CPU를 할당받음
🔗실행
- 준비 상태에서 CPU 스케줄러에 의해 선택된 프로세스가 실행되고 있는 상태
- 실행 상태에 있는 프로세스의 숫자는 CPU의 숫자와 같다
- 실행 상태에 있더라도 부여된 시간만큼만 CPU를 사용할 수 있다
- 부여된 시간을 모두 사용하면 다시 준비 상태로 돌아간다
🔗대기
- 프로세스가 입출력 요청을 하면 입출력이 완료될 때까지 기다리는 상태
- CPU의 속도에 비해 입출력 작업은 느리다. 이를 해결하기 위해 입출력 요청을 한 프로세스를 대기 상태에 두고 다른 프로세스를 먼저 실행한다. 그 후 입출력 작업이 완료되면 대기 상태에 있던 프로세스를 준비 상태로 옮겨서 실행되도록 한다.
🔗완료
- 프로세스가 종료된 상태
- 프로세스가 사용한 데이터를 메모리에서 제거하고 생성된 PCB도 제거한다.
컨텍스트 스위칭
컨텍스트 스위칭
🔗프로세스를 실행하는 중에 다른 프로세스를 실행하기 위해 실행 중인 프로세스의 상태를 저장하고 다른 프로세스의 상태값으로 교체하는 작업
🔗컨텍스트 스위칭이 일어나면 PCB의 내용이 변경된다
- 실행 중인 프로세스의 작업 내용을 PCB에 저장하고 실행될 프로세스의 PCB 내용대로 CPU가 세팅된다
- 프로세스 상태, 프로그램 카운터, 각종 레지스터 값 등이 변경된다
프로세스 생성과 종료
프로세스 생성 과정
🔗프로그램의 코드 영역과 데이터 영역을 메모리에 로드하고 빈 스택과 힙을 만들어 공간을 확보한다.
🔗프로세스를 관리하기 위한 PCB를 만들어서 값을 초기화한다.
🔗프로세스 생성 과정은 운영체제가 부팅되고 0번 프로세스가 생성될 때 딱 한 번만 실행된다.
- 나머지 모든 프로세스는 fork() 함수를 이용해 0번 프로세스를 복사해서 쓴다. 복사해서 쓰는 게 더 빠르기 때문.
- 복사해서 생성된 프로세스를 자식 프로세스라고 하며, 0번 프로세스는 부모 프로세스가 된다.
- 이후 exec() 함수를 실행하면 자식 프로세스의 코드와 데이터 영역을 원하는 값으로 덮어쓰게 된다.
🔗예제 코드
부모 프로세스
#include <stdio.h>
#include <unistd.h>
int main()
{
int pid;
pid = fork(); //부모 프로세스에게는 0이 아닌 숫자를 반환
if(pid == 0) //자식 프로세스
{
execlp("InternetBrowser", "0", NULL);
exit(0);
}
else // 부모 프로세스
{
wait(NULL); //자식 프로세스에서 exit() 신호가 올 때까지 기다렸다가 신호가 오면 종료시킴
printf("인터넷 브라우져 닫힘");
exit(0);
}
}
자식 프로세스
#include <stdio.h>
#include <unistd.h>
int main()
{
int pid;
pid = fork(); //자식 프로세스에는 0을 반환
if(pid == 0) //자식 프로세스
{
execlp("InternetBrowser", "0", NULL); //인터넷 브라우저 프로그램 실행 후 해당 프로그램에서 코드와 데이터 영역을 가져와 덮어씀
exit(0); //프로세스 종료를 알림
}
else // 부모 프로세스
{
wait(NULL); //
printf("인터넷 브라우져 닫힘");
exit(0);
}
}
🔗두 프로세스 중 어떤 프로세스가 먼저 실행될지는 운영체제가 선택한다.
🔗부모 프로세스가 자식 프로세스보다 먼저 종료되거나 자식 프로세스가 비정상적으로 종료돼 exit() 신호를 주지 못해서 메모리에 계속 살아 있는 상태를 "좀비 프로세스"라고 부른다.
쓰레드
쓰레드
🔗프로세스가 메모리를 많이 차지하는 문제를 해결하기 위해 고안된 작업의 실행 단위
🔗한 프로세스 내의 쓰레드들은 그 프로세스의 PCB, 코드, 데이터, 힙 영역을 공유한다. 스택은 쓰레드마다 각각 가지고 있다.
🔗쓰레드 ID: 쓰레드를 구분하기 위한 식별자
🔗Thread Control Block(TCB): 쓰레드를 관리함
🔗프로세스를 복사해서 새로 생성하는 대신 쓰레드를 여러 개 추가해서 메모리를 절약한다.
프로세스 vs 쓰레드
🔗프로세스
-
- 프로세스는 서로 독립적이기 때문에 한 프로세스에 문제가 생기더라도 다른 프로세스가 영향을 받지 않는다.(안정성 좋음)
- 오버헤드가 크고 속도가 느리다.(각 프로세스마다 PCB와 데이터, 힙, 스택 영역을 전부 갖고 있고 프로세스간 통신에 IPC를 이용하기 때문)
🔗쓰레드
-
- 쓰레드는 하나의 프로세스 내에 존재하기 때문에 해당 프로세스에 문제가 생기면 그 안의 모든 쓰레드에 문제가 생긴다.(안정성 나쁨)
- 한 프로세스 내에서 스택 영역을 제외한 모든 영역을 공유하기 때문에 오버헤드가 적다.
'운영체제 > 그림으로 쉽게 배우는 운영체제(인프런 강의)' 카테고리의 다른 글
메모리 종류 (0) | 2022.03.29 |
---|---|
데드락 (0) | 2022.03.29 |
프로세스 동기화 (0) | 2022.03.28 |
CPU 스케줄링 (0) | 2022.03.25 |
운영체제 들어가기 (0) | 2022.03.21 |