흔히 말하는 응용 소프트웨어 또는 애플리케이션들을 프로그램이라고 한다. 카카오톡이나 워드, 웹 브라우저 등 모두 프로그램이다.
좀 더 사전적인 의미로 들어가면, 특정 문제를 해결하기 위해 처리 방법과 순서를 기술하여 컴퓨터에 입력되는 일련의 명령문 집합체로, 대부분의 프로그램들은 하드디스크와 같은 매체에 바이너리 형식의 파일로 저장되어 있다가 사용자가 실행시키면 메모리에 적재되어 실행된다.
프로세스는 실행중에 있는 프로그램을 의미한다. 하드디스크에 저장되어 있는 프로그램을 실행시키면 운영체제로부터 메모리 할당이 이루어지고, 할당된 메모리 공간에 바이너리 코드가 올라가게 되는데, 이 순간부터 프로세스라고 불린다. 즉 프로그램의 instatnce이다.
프로세스는 메모리 공간에서 독립적으로 공간을 할당받는다.
- Code : 실행할 프로그램의 코드가 저장되는 영역, 텍스트 영역이라고도 하며, CPU는 코드 영역에 저장된 명령어를 하나씩 가져가서 처리
- Data: 프로그램의 전역변수와 정적 변수가 저장되는 영역, 프로그램 시작과 함께 할당되며, 종료 시 소멸
- Stack: 함수의 호출과 관계되는 지역변수와 매개변수가 저장되는 영역, 함수의 호출과 함께 할당되며, 함수의 호출이 완료되면 소멸
- 힙: 사용자가 직접 관리할 수 있는 메모리 영역, 사용자에 의해 메모리 공간이 동적으로 할당 및 해제됨
JVM 환경은 다름. 추후 포스팅 예정
자료 출처: https://jerry92k.tistory.com/58
- New : 메인 메모리에 막 올라온 상태, 아직 실행은 불가능
- Ready : 변수 초기화 등 기초 준비 작업을 끝내고 실행을 할 수 있는 상태
- Running : 실제로 프로세스가 수행되고 있는 상태
- Terminated : 프로세스가 종료된 상태, 할당 받은 메모리 영역 해제
- Waiting : I/O 작업이 필요하여 I/O 작업을 수행하는 상태이다. CPU는 I/O를 기다리며, 다른 프로세스를 수행한다. I/O 작업이 종료되면 다시 Ready 상태가 된다.
PCB란 운영체제가 프로세스를 제어하기 위해 정보를 저장한 자료구조로, 프로세스의 상태 정보를 저장한다. 각 프로세스가 생성될 때마다, PCB가 생성되고 프로세스가 종료되면 PCB는 제거된다.
PCB는 Linked List 형식으로 연결된다.
운영체제에 따라 항목이 다르지만, 일반적으로 다음같은 정보들이 포함된다.
포인터: 프로세스의 현재 위치를 저장하는 포인터
프로세스 상태: 프로세스의 각 상태 저장
프로세스 번호: 프로세스는 식별할 수 있는 고유의 프로세스 ID(PID) 저장
프로그램 카운터: 프로세스를 위해 실행될 다음 명령어의 주소를 포함하는 카운터를 저장
레지스터 : CPU 레지스터에 있는 정보
메모리 제한 : 운영체제에서 사용하는 메모리 관리 시스템에 대한 정보, 페이지 테이블, 세그먼트 테이블 등
열린 파일 목록: 프로세스를 위해 열린 파일 목록
운영체제는 프로세스 테이블을 이용해서 각 프로세스의 PCB를 관리한다.
프로세스가 이미 CPU를 사용 중인 상태에서 다른 프로세스가 CPU를 사용하기 위해 이전 프로세스 상태를 저장하고 새로운 프로세스의 상태럴 적재하는 것.
즉 CPU는 동시에 프로세스를 사용하는 것처럼 보이지만, 실제로는 재빠르게 프로세스를 번갈아가며 실행하고 있는 것
스레드란 프로세스 내에서 실제로 작업을 수행하는 주체를 의미한다. 모든 프로세스는 최소 1개 이상의 스레드가 존재하여 작업을 수행한다.
스레드는 스레드 ID, 프로그램 카운터, 레지스터 집합, 스택으로 구성된다.
오른쪽 그림과 같이, 2개 이상의 스레드를 가지는 프로세스를 멀티스레드 프로세스라고 한다. 멀티스레드는 프로세스 내에서 각각의 독립된 스택을 가지며, 코드, 데이터, 힙 영역을 공유한다.
멀티 프로세스의 경우, 각각의 메모리 영역은 독립적으로 존재한다.
멀티 스레드 예시 코드
import threading
# 전역 변수
counter = 0
# 전역 변수를 수정하는 함수
def increment_counter():
global counter
for _ in range(1000000):
counter += 1
# 두 개의 스레드 생성
thread1 = threading.Thread(target=increment_counter)
thread2 = threading.Thread(target=increment_counter)
# 스레드 실행
thread1.start()
thread2.start()
# 모든 스레드의 실행이 끝날 때까지 기다림
thread1.join()
thread2.join()
print("최종 카운터 값:", counter)
최종 카운터 값: 1618313 // 실행마다 다름
https://blockdmask.tistory.com/22
https://pages.cs.wisc.edu/~remzi/OSTEP/Korean/04-cpu-intro.pdf
https://gusdnd852.tistory.com/82
https://yoongrammer.tistory.com/52
https://velog.io/@aeong98/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9COS-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C