프로세스
📌 실행 중인 프로그램을 의미합니다. 프로그램을 실행하면 OS로부터 실행에 필요한 자원(메모리)를 할당받아 프로세스가 됩니다. 프로세스는 운영체제의 주요 관리 단위이며, 독립적으로 실행됩니다.
1. 프로세스의 구성 요소
- 코드 영역(Code Segment)
실행할 프로그램의 명령어가 저장된 영역. CPU는 여기서 명령을 읽어 실행합니다.
- 데이터 영역(Data Segment)
전역 변수와 정적 변수가 저장되는 영역.
- 힙 영역(Heap Segment)
실행 중 동적으로 할당된 메모리가 저장되는 영역. 예: malloc()이나 new를 통한 메모리 할당. (객체, 변수등 저장)
- 스택 영역(Stack Segment)ㄴ
함수 호출 시 사용되는 메모리 영역으로, 지역 변수와 함수 호출 정보를 저장.(호출에 필요한 참조 정보 저장)
- 간단하게는, 자원 + 쓰레드 단수~복수로 이루어져 있다. 공장(프로세스)에서 월급(자원)받아 일하는 일꾼(쓰레드)
2. 프로세스의 상태
프로세스는 실행 중 다양한 상태를 가집니다. 대표적인 상태는 다음과 같습니다:
- New (생성): 프로세스가 생성되고 초기화 중인 상태.
- Ready (준비): 실행되기를 기다리는 상태. CPU가 사용 가능할 때 실행됨.
- Running (실행): CPU에서 명령어가 실행 중인 상태.
- Waiting (대기): I/O 작업 같은 이벤트를 기다리는 상태.
- Terminated (종료): 실행을 완료한 상태.
3. 프로세스와 쓰레드
- 프로세스는 프로그램 실행의 독립적인 단위이며, 다른 프로세스와 메모리 공간을 공유하지 않습니다.
- 쓰레드는 프로세스 내에서 실행되는 작업의 흐름으로, 같은 프로세스의 메모리 공간을 공유합니다. (멀티쓰레드를 사용하는 이유는 효율적인 자원 사용과 빠른 동작을 위함입니다.)
- 기본적으로 쓰레드는 같은 프로세스의 메모리 공간을 공유하지만, 스택은 예외적으로 스레드마다 독립적인 스택을 가집니다. (매개변수, 리턴 주소, 지역 변수 등)
4. 프로세스 간 통신 (IPC: Inter-Process Communication)
프로세스는 독립적이지만, 특정 경우 데이터를 공유하거나 협력하기 위해 통신합니다. 주요 방법은 다음과 같습니다:
- 파이프(Pipe): 한쪽에서 쓰면 다른 쪽에서 읽는 방식.
- 메시지 큐(Message Queue): 메시지를 보내고 받는 방식.
- 공유 메모리(Shared Memory): 프로세스들이 특정 메모리 공간을 공유.
- 소켓(Socket): 네트워크 통신 기반의 프로세스 간 통신.
5. 프로세스 관리
운영체제는 프로세스를 다음과 같은 방식으로 관리합니다:
- 프로세스 생성: fork() (UNIX 계열) 또는 CreateProcess() (Windows)를 통해 생성.
- 스케줄링: CPU 시간을 효율적으로 분배. 대표적인 알고리즘은 Round Robin, FIFO, Priority Scheduling 등이 있습니다.
- 프로세스 종료: 실행이 끝나거나 강제로 종료(kill, terminate).
6. 프로세스의 예시
- 사용자가 웹 브라우저를 실행 -> 브라우저는 새로운 프로세스 생성.
- 브라우저가 탭마다 새로운 프로세스를 생성 -> 충돌 방지 및 독립성 보장.
쓰레드
📌 프로세스 내에서 실행되는 작업의 단위입니다. 하나의 프로세스는 여러 쓰레드를 가질 수 있으며, 이를 통해 병렬 작업(멀티쓰레딩)을 수행할 수 있습니다. 쓰레드는 프로세스의 자원을 공유하면서 독립적인 실행 흐름을 가집니다.
1. 쓰레드의 특징
- 독립적인 실행 흐름
- 쓰레드는 프로세스 내에서 별도의 실행 흐름을 가집니다.
- 운영체제는 각 쓰레드에 CPU 시간을 할당하여 동시에 실행되는 것처럼 보이게 만듭니다(멀티태스킹).
- 메모리 공간 공유
- 같은 프로세스 내 쓰레드는 코드, 데이터, 힙 영역을 공유합니다.
- 하지만 각 쓰레드는 자신만의 스택(Stack) 공간을 가집니다.
- 경량 프로세스
- 쓰레드는 프로세스에 비해 생성, 스위칭, 종료가 더 빠르고 자원 소모가 적습니다.
2. 쓰레드의 메모리 구조
- 공유되는 영역
- 코드 영역: 실행할 명령어 공유.
- 데이터 영역: 전역 변수 및 정적 변수 공유.
- 힙 영역: 동적으로 할당된 객체 공유.
- 독립적인 영역
- 스택 영역: 각 쓰레드마다 고유한 스택을 가집니다. 함수 호출 시 매개변수, 지역 변수, 리턴 주소 등이 저장됩니다.
3. 쓰레드의 동작 방식
- 쓰레드는 운영체제의 스케줄러에 의해 실행 상태가 관리됩니다.
- 생성 → 실행 → 대기 → 종료 상태를 거칩니다.
- 같은 프로세스 내의 쓰레드는 자원을 공유하므로, 동시에 작업을 수행할 수 있지만 동기화가 필요할 때도 있습니다.
+ 다수의 쓰레드가 동시에 공유데이터에 접근하면 데이터가 훼손되는 문제가 생기기도 합니다. 이를 방지하기 위해 동기화라는 작업을 수행합니다.
4. 멀티쓰레드의 장점과 단점
장점:
- 병렬 처리: 여러 작업을 동시에 처리하여 성능 향상.
- 자원 공유: 프로세스 자원을 공유하므로 효율적.
- 빠른 생성과 종료: 새로운 프로세스를 생성하는 것보다 경량.
단점:
- 동기화 문제: 자원 접근 시 충돌을 방지하기 위해 동기화가 필요 (예: 뮤텍스, 세마포어).
- 디버깅의 어려움: 병렬 처리로 인해 버그를 재현하거나 추적하기 어려움.
- 컨텍스트 스위칭 비용: 스케줄러가 쓰레드를 전환할 때 약간의 오버헤드 발생.
5. 쓰레드 생성 방법
1) Java에서의 쓰레드 생성
- Thread 클래스 상속
- Runnable 인터페이스 구현
위의 2개의 방식이 일반적이지만, Thread의 경우 엄연히 클래스임으로 Thread를 사용할 경우 다른 class를 상속할 수 없습니다.(자바는 다중 상속이 안되지만 C의 경우 가능합니다.) 그래서 일반적으로는 Runnable 인터페이스로 구현합니다.
class MyRunnable implements Runnable {
public void run() {
System.out.println("Thread is running...");
}
}
public class Main {
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start();
}
}
class MyThread extends Thread {
public void run() {
System.out.println("Thread is running...");
}
}
public class Main {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
}
}
6. 쓰레드와 동기화
- 멀티쓰레드 환경에서는 여러 쓰레드가 동시에 공유 자원에 접근할 때 문제가 발생할 수 있습니다.
- 동기화 기법:
- 뮤텍스(Mutex): 한 번에 하나의 쓰레드만 자원 접근 허용.
- 세마포어(Semaphore): 지정된 수의 쓰레드만 자원 접근 허용.
- 모니터(Monitor): Java의 synchronized 키워드 사용.
7. 쓰레드와 프로세스의 차이
|
프로세스 |
쓰레드 |
기본 단위 |
독립적인 실행 단위 |
프로세스 내 실행 단위 |
메모리 공간 |
독립적인 메모리 공간을 가짐 |
같은 프로세스 내에서 메모리 공간을 공유 |
자원 사용 |
각 프로세스는 독립적인 자원(파일, 메모리 등)을 가짐 |
자원을 공유하며, 프로세스 내에서 자원 경쟁이 발생할 수 있음 |
통신 |
프로세스 간 **IPC(Inter-Process Communication)**가 필요 |
같은 프로세스 내에서 쉽게 통신할 수 있음 |
생성 비용 |
상대적으로 높은 비용과 시간이 소요됨 |
상대적으로 적은 비용과 시간으로 생성 가능 |
스케줄링 |
운영체제가 독립적으로 관리 |
쓰레드는 운영체제의 스케줄링과 각 쓰레드 간의 스케줄링이 필요 |
main 쓰레드
📌 프로그래밍에서 항상 사용하는 main메서드의 작업을 수행하는 쓰레드를 의미합니다.
- 아무리 짧은 프로그램이라도 일꾼이 있어야 프로그램이 돌아가는 만큼, 쓰레드가 존재합니다.