본문 바로가기

CS 스터디/운영체제

프로세스와 스레드

프로세스(Process)

  • 컴퓨터에서 실행되고 있는 프로그램
  • 프로그램으로부터 인스턴화된 것
  • chrome.exe (프로그램) -> 두 번 클릭(실행시킴) -> chrome process
  • CPU 스케쥴링의 대상이 되는 작업(task)

프로세스 실행 과정

1. 프로그램이 메모리에 올라감

2. 인스턴스화 (프로그램 -> 프로세스)

3. CPU 스케줄러에 따라 CPU가 해당 프로세스 실행

 

프로그램

  • 컴파일러가 컴파일 과정을 거쳐 컴퓨터가 이해할 수 있는 기계어로 번역되어 실행될 수 있는 파일
  • 컴파일: 사람이 작성한 소스코드를 컴퓨터가 이해할 수 있게 기계어로 해석하는 과정 (프로그래밍 언어 -> 기계어) 

 

컴파일 과정

1. 전처리

2. 컴파일러

3. 어셈블러

4. 링커

 

 

1. 전처리

  • 소스 코드의 주석 제거
  • #include 등 헤더 파일 병합하여 매크로 치환

출처: https://udonudon.tistory.com/44

 

2. 컴파일러

3. 어셈블러

  • 목적 코드(object code)로 변환
  • 목적 코드: 프로세서가 이해할 수 있는 명령어의 형태 (<-> 원시코드)
  • 1. 명령어 생성: 원시 프로그램에 있는 기호 명령어를 분석하여 기계어 명령어로 변경 ex) MOV -> 10110100(B4)
  • 2. 기계 주소 할당: 원시 프로그램에 있는 기호 번지(변수)나 상수의 기억 장소(절대 번지)를 할당 ex) KOR -> [01000], 65 ->[0100001]
  • 3. 의사 명령어 처리: 프로그램의 시작과 종료, 재배치 정보 등 프로그램의 안내자 역할을 하는 명령어들 처리 ex) START, END

4. 링커

  • 프로그램 내의 라이브러리 함수 또는 다른 파일들과 목적 코드를 결합하여 실행 파일 생성
  • .exe 또는 .out이라는 확장자

라이브러리

  정적 라이브러리 동적 라이브러리
방식 프로그램 빌드 시(컴파일 타임), 라이브러리가 제공하는 모든 코드를 실행 파일에 넣는 방식

라이브러리 내용 모두 메모리에 로드
프로그램 실행 시(런타임), 필요할 때만 DLL이라는 함수 정보를 통해 참조하는 방식

메모리에 이미 존재하는 경오, 로드 시간/공간 절약, BUT 매번 메모리에 접근해야함 -> 오버헤드 존재(느림)
의존도 외부 의존도 낮음(시스템 환경 등) 외부 의존도 높음
효율성 메모리 효율성 낮음(코드 중복 등) 메모리 효율성 높음

 

 

프로세스 상태

1. 생성 상태

2. 대기 상태

3. 대기 중단 상태

4. 실행 상태

5. 중단 상태

6. 일시 중단 상태

7. 종료 상태

 

1. 생성 상태(create)

  • 프로세스가 생성된 상태
  • fork() or exec() 함수를 통해 생성됨
  • PCB(Process Control Block)가 할당됨

fork()

  • 부모 프로세스의 주소 공간을 그대로 복사
  • 새로운 자식 프로세스를 생성하는 함수, 원래 프로세스는 기존의 하던 작업 실행
  • -> 새로운 프로세스를 위한 메모리 할당
  • -> fork()의 결과는 프로세스 하나가 더 생김 = PID(Process Id)가 완전히 다른 또 하나의 프로세스가 생김
  • 단순 주소 공간만 복사
  • 부모 프로세스의 비동기 작업 등을 상속 X

exec()

  • 새로운 프로세스를 위한 메모리 할당 X
  • exec()를 호출한 프로세스가 아닌 exec()에 의해 호출된 프로세스만 메모리에 남게됨
  • exec()의 결과는 생성된 새로운 프로세스는 업속, exec()를 호출한 프로세스의 PID가 그대로 새로운 프로세스에 적용
  • -> exec()를 호출한 프로세스는 새로운 프로세스에 의해 덮어 쓰여짐

 

2. 대기 상태(ready)

  • 메모리 공간이 충분하면 메모리 할당 받음
  • 충분하지 않으면 할당받지 않은 상태로 대기
  • CPU 스케줄러로부터 CPU 소유권이 넘어오길 기다리는 상태

 

3. 대기 중단 상태(ready suspended)

  • 메모리 부족으로 일시 중단된 상태

 

4. 실행 상태(running)

  • CPU 소유권과 메모리를 할당받고 인스트럭션을 수행 중인 상태, CPU burst가 일어났다고 표현
  • 인스트럭션: 컴파일된 소스 코드로 실행 파일 한 줄 한 줄의 명령어

 

5. 중단 상태(blocked)

  • 어떤 이벤트가 발생한 후, 기다리며 프로세스가 차단된 상태
  • I/O 디바이스에 의한 인터럽트로 자주 발생
  • ex) 프린트 인쇄 버튼 클릭 시, 프로세스가 잠깐 멈추는 경우

 

6. 일시 중단 상태(blocked suspended)

  • 대기 중단 상태와 유사
  • 중단된 상태에서 프로세스가 실행되려고 했지만 메모리 부족으로 일시 중단된 상태

 

7. 종료 상태(terminated)

  • 메모리와 CPU 소유권 모두 놓고 가는 상태
  • 자발적 종료: 자연스럽게 종료됨
  • 비자발적 종료(abort)
  • ex) 부모 프로세스가 자식 프로세스를 강제로 종료
  • ex) 자식 프로세스에 할당된 자원의 한계치를 넘어섬
  • ex) 사용자가 process.kill 등의 명령어로 프로세스 종료

 

* 위의 7가지 단계에 대한 내용은 책의 그림 참고하면 좋을 것 같음 *

 

출처: https://itwiki.kr/w/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4_%EC%83%81%ED%83%9C

 

프로세스 상태를 나타내는 교재 외의 그림

 

 

프로세스의 메모리 구조

1. 스택

2. 힙

3. 데이터 영역

4. 코드 영역

 

 

1. 스택(Stack)

  • 지역 변수, 매개 변수, 함수가 저장됨
  • 컴파일 시에 크기가 결졍되는 동적인 특징
  • 함수가 함수를 재귀적으로 호출
  • -> 동적으로 크기 증가
  • -> 힙과 스태그이 메모리 영역이 겹치면 안되기 때문에 힙과 스택 사이의 공간은 비워둠
  • 스택은 위의 주소부터 할당됨

 

2. 힙(Heap)

  • 동적 할당할 때 사용됨 (new @@)
  • 런타임 시 크기가 결정됨 (<-> 스택: 컴파일 시 크기 결정됨)
  • ex) 벡터와 같은 동적 배열
  • 아래의 주소부터 할당됨

 

3. 데이터 영역(BSS segment + Data segment)

  • 전역 변수, 정적 변수 저장됨
  • 정적인 특징을 갖는 프로그램이 종료되면 사라지는 변수들의 영역
  • BSS 영역, Data 영역으로 나뉨
  • BSS(Block Started by Symbol) 영역: 초기화되지 않는 변수가 0으로 초기화되어 저장됨
  • Data 영역: 0이 아닌 다른 값으로 할당된 변수들이 저장됨

 

4. 코드 영역(code segment)

  • 프로그램에 내장되어 있는 소스 코드가 들어있는 영역
  • 수정 불가능한 기계어로 저장되어 있는 정적인 영역

 

 

PCB(Process Control Block)

  • 프로세스에 대한 메타데이터를 저장한 데이터
  • 프로세스가 생성되면 운영체제에서 해당 PCB를 생성
  • 프로그램 실행
  • -> 프로세스 생성
  • -> 프로세스 주소 값들에 메모리 할당
  • -> 프로세스의 메타데이터들이 PCB에 저장 및 관리됨
  • 프로세스의 중요 정보이기 때문에 일반 사용자 접근 불가 -> 커널 스택의 가장 앞부분에서 관리

 

메타데이터

  • 데이터에 관한 구조화된 데이터
  • 데이터를 설명하는 작은 데이터
  • 대량의 정보 가운데에서 찾고 있는 정보를 효율적으로 찾아내서 이용하기 위해 일정한 규칙에 따라 콘텐츠에 대해 부여되는 데이터

 

PCB 구조

1. 프로세스 스케줄링 상태

  • '준비', '일시중단' 등 프로세스가 CPU에 대한 소유권을 얻은 이후의 상태

2. 프로세스 ID(PID)

  • 해당 프로세스의 자식 프로세스 ID ???
  • 유닉스, 맥 OS X 또는 마이크로소프트 윈도우 등의 운영 체제 커널이 사용되는 번호
  • PID를 통해 어떤 한 프로세스를 일시적으로 식별 가능

3. 프로세스 권한

  • 컴퓨터 자원 또는 I/O 디바이스에 대한 권한 정보

4. 프로그램 카운터(PC)

  • 프로세스에서 실행해야 할 다음 명령어의 주소에 대한 포인터

5. CPU 레지스터

  • 프로세스를 실행하기 위해 저장해야 할 레지스터에 대한 정보
  • 레지스터: 컴퓨터의 프로세서 내에서 자료를 보관하는 아주 빠른 기억 장소

6. CPU 스케줄링 정보

  • CPU 스케줄러에 의해 중단된 시간 등에 대한 정보

7. 계정 정보

  • 프로세스 실행에 사용된 CPU 사용량, 실행한 유저의 정보

8. I/O 상태 정보

  • 프로세스에 할당된 I/O 디바이스 목록

 

컨텍스트 스위칭(Context Switching)

  • PCB 교환 과정
  • 기존의 프로세스에 할당된 시간이 끝나거나 인터럽트에 의해 발생
  • 다수의 프로그램이 동시에 실행되는 것처럼 보이지만, 실상은 어떠한 시점에서 실행되고 있는 프로세스는 단 1개
  • 아주 빠른 속도로 컨텍스트 스위칭이 일어나고 있는 것
  • 현대 컴퓨터는 멀티코어의 CPU를 갖고 있기 때문에 위의 설명은 틀린 설명이지만, 싱글 코어 기준으로 설명
  • 컨텍스트 스위칭이 일어나는 과정에서 유휴시간(idle time) 발생
  • 컨텍스트 스위칭에 발생하는 비용 존재(캐시미스)
  • 프로세스 뿐만 아니라 스레드에서도 컨텍스트 스위칭 발생
  • 스레드는 스택 영역을 제외한 나머지 모든 메모리 공간을 공유하기 때문에 보다 비용이 적고 시간이 적게 소요됨

캐시미스(비용)

- 컨텍스트 스위칭이 일어날 때 프로세스가 가지고 있는 메모리 주소가 그대로 있다면, 잘못된 주소 변환이 생기므로 캐시클리어 과정을 겪게 되는데 이 과정에서 캐시미스가 발생

 

 

멀티프로세싱

  • 동시에 두 가지 이상의 일(프로세스)을 진행 가능한 것
  • 하나 이상의 일을 병렬로 처리 가능
  • -> 특정 프로세스의 메모리, 프로세스 중 일부에 문제가 발생하더라도, 다른 프로세스 이용가능하기 때문에 처리 가능
  • -> 신뢰성 높음
  • 웹 브라우저는 멀티프로세스 구조을 갖고 있음

 

ex) 웹 브라우저의 멀티프로세싱

1. 브라우저 프로세스

- 주소 표시줄, 북마크 막대, 뒤로 가기 버튼, 앞으로 가기 버튼 등을 담당하며 네트워크 요청이나 파일 접근 같은 권한 담당

 

2. 랜더러 프로세스

- 웹 사이트가 "보이는" 부분의 모든 것을 제어

 

3. 플러그인 프로세스

- 웹 사이트에서 사용하는 플러그인을 제어함

 

4. GPU 프로세스

- GPU를 이용해서 화면을 그리는 부분을 제어

 

 

IPC(Inter Process Communication)

  • 프로세스끼리 데이터를 주고 받고, 공유 데이터를 관리하는 메커니즘
  • ex) 클라이언트와 서버 간의 요청, 응답 과정

 

IPC 종류

- 메모리가 완전히 공유되는 스레드보다는 비교적 속도가 느림

1. 공유 메모리

2. 파일

3. 소켓

4. 익명 파이프

5. 명명 파이프

6. 메시지 큐

 

 

1. 공유 메모리(Shared Memory)

  • 여러 프로세스에 동일한 메모리 블록에 대한 접근 권한이 부여되어 프로세스가 서로 통신할 수 있도록 공유 버퍼를 생성
  • 원래 각 프로세스의 메모리에 다른 프로세스가 접근 불가능하지만, 공유 메모리를 통해 여러 프로세스가 특정 메모리 공유 가능
  • 어떤 매개체를 통해 데이터를 주고 받는 방식이 아니라 메모리 자체를 공유함
  • -> 불필요한 데이터 복사의 오버헤드 발생 X -> 가장 빠름
  • -> 같은 메모리 영역을 여러 프로세스가 공유하기 때문에 동기화 필요 
  • ex) CPU가 접근할 수 있는 큰 랜덤 메모리인 RAM도 하드웨어 관점에서 공유 메모리

2. 파일

  • 디스크에 저장된 데이터 또는 파일 서버에서 제공한 데이터
  • 이를 기반으로 프로세스 간 통신
  • 텍스트 파일(혹은 다른 포멧의 파일)을 통해 데이터를 주고 받는 것도 IPC 기법 중 하나
  • -> 실시간으로 직접 원하는 프로세스에 데이터를 전달하는 것이 어려움 -> 디스크에서 데이터 파일을 읽고 프로세스에 적재되는 과정에서 컨텍스트 스위칭, 인터럽트 등의 일 처리 필요 -> 문제 많음

3. 소켓

  • 동일한 컴퓨터의 다른 프로세스나 네트워크의 다른 컴퓨터로 네트워크 인터페이스를 통해 전송하는 데이터
  • 서버와 클라이언트가 특정 포트를 통해 실시간으로 양방향 통신하는 방식
  • 패킷 단위로 주고 받음으로서 직관적으로 이해하기 쉬움
  • 서버 소켓: 서버 프로그램에서만 사용하는 소켓, 클라이언트로부터 연결 요청이 오기를 기다렸다가 연결 요청이 들어오면, 클라이언트와 연결을 맺고 다른 소켓을 만드는 일을 함
  • 클라이언트 소켓: 대기하지 않고 클라이언트 소켓 생성, 클라이언트 프로그램에서 클라이언트 소켓은 서버 프로그램으로 연결 요청하는 것데이터를 전송하는 일을 함, 실제로 송수신이 일어나는 소켓
  • TCP, UDP

4. 익명 파이프(Anonymouse pipe)

  • 프로세스 간에 FIFO 방식으로 읽히는 임시 공간인 파이프를 기반으로 데이터를 통신
  • 단방향 방식의 읽기 전용, 쓰기 전용 파이프를 만들어서 작동하는 방식
  • 부모, 자식 프로세스 간에만 사용 가능, 부모와 자식 프로세스만이 파일 디스크립터를 공유하므로
  • 다른 네트워크 상에서는 불가능

파일 디스크립터: 특정한 파일로 접근하기 위한 추상적인 키

 

5. 명명된 파이프(named pipe)

  • 파이프 서버와 하나 이상의 파이프 클라이언트 간의 통신을 위한 명명된 단방향 또는 이중 파이프
  • 클라이언트/서버 통신을 위한 별도의 파이프 제공
  • 다수의 파이프를 동시 사용 가능
  • 컴퓨터의 프로세스끼리 뿐만 아니라 다른 네트워크 상의 컴퓨터와 통신 가능 (지정한 이름으로 파일 디스크립터를 열 수 있기 때문)
  • 서버용 파이프와 클라이언트용 파이프로 구분하여 작동
  • 하나의 인스턴스를 열거나 다수의 인스턴스를 기반으로 통신

6. 메시지 큐(queue)

  • 메시지를 큐(queue) 데이터 구조 형태로 관리
  • 입출력 방식은 익명 파이프와 동일하지만, 커널에서 관리하며 메모리를 사용한 파이프, 구조체를 기반으로 통신
  • 파이프와 다르게 데이터의 흐름이 아니라 메모리 공간
  • 다른 IPC 방식에 비해 사용방법이 매우 직관적, 간단함
  • 다른 코드의 수정 없이 몇 줄의 코드만 추가하여 간단히 메시지 큐에 접근 가능
  • 공유 메모리(1.) 동기화 때문에 기능 구현이 매우 복잡하여, 이를 대안으로 메시지 큐 사용

 

보다 자세한 설명: https://doitnow-man.tistory.com/110

 

 

스레드

  • 프로세스의 실행 가능한 가장 작은 단위
  • 다수의 스레드를 가질 수 있음
  • 코드, 데이터, 힙은 스레드끼리 서로 공유 -> 각각 생성하는 프로세스보다 비교적 빠름
  • 그 외의 영역은 각자 생성

멀티스레딩

  • 프로세스 내의 작업을 여러 개의 스레드로 처리하는 기법
  • 스레드끼리 자원을 공유하기 떄문에 효율성 높음
  • ex) 웹 요청 처리 시, 새로운 프로세스를 생성하는 대신 스레드를 사용하면 웹 서버의 경우 훨씬 적은 리소스 소비
  • 한 스레드가 중단(blocked)되어도 다른 스레드는 실행(running) 상태 일 수 있어서 중단되지 않고 빠른 처리 가능
  • 동시성 장점
  • 한 스레드에 문제가 생기면 다른 스레드에도 영향을 끼칠 수 있음(자원을 공유하고 있기 때문) -> 스레드로 이뤄진 프로세스에 영향을 줄 수 있는 단점

동시성

- 서로 독립적인 작업들을 작은 단위로 나누고 동시에 실행되는 것처럼 보여주는 것

 

 

멀티스레드 예시(웹 브라우저의 렌더러 프로세스)

1. 메인 스레드

2. 워커 스레드

3. 컴포지터 스레드(레이어 합성)

4. 레스터 스레드(화면을 픽셀로 변환)

 

 

공유 자원(Shared Resource)

  • 시스템 안에서 각 프로세스, 스레드가 함께 접근할 수 있는 모니터, 프린터, 메모리, 파일, 데이터 등의 자원이나 변수
  • 2개 이상의 프로세스가 동시에 읽거나 쓰는 상황 == 경쟁 상태(race condition)
  • 동시에 접근을 시도할 때, 접근의 타이밍이나 순서 등이 결과값에 영향을 줄 수 있는 상태 (동시성 문제)

임계 영역(critical section)

  • 둘 이상의 프로세스, 스레드가 공유 자원에 접근할 때 순서 등의 이유로 결과가 달라지는 코드 영역
  • 위 문제를 해결하기 위한 방법 
  • 1. 뮤텍스 2. 세마포어 3. 모니터
  • -> 상호 배제, 한정 대기, 융통성이라는 조건 만족
  • 잠금(lock) 메커니즘을 토대로 사용

1. 상호 배제

- 한 프로세스가 임계 영역에 들어갔을 때, 다른 프로세스는 들어가지 못함

 

2. 한정 대기

- 특정 프로세스가 영원히 임계 영역에 들어가지 못하면 안됨, 언젠가는 들어가야 함

 

3. 융통성

- 한 프로세스가 다른 프로세스의 일을 방해해서는 안됨

 

 

뮤텍스(Mutex)

  • 프로세스나 스레드가 공유 자원을 lock()을 통해 잠금 설정하고 이용한 후, unlock()을 통해 잠금 해제하는 객체
  • 잠금 또는 잠금 해제라는 상태만 가짐

세마포어(Semaphore)

  • 일반화된 뮤텍스
  • 간단한 정수 값 + 2가지 함수(wait, signal)로 공유 자원에 대한 접근 처리
  • wait(), P 함수: 자신의 차례가 올 때까지 기다리는 함수
  • signal(), V 함수: 다음 프로세스로 순서를 넘겨주는 함수
  • 프로세스나 스레드가 공유 자원에 접근하면 세마포어에서 wait() 작업 수행
  • 프로세스나 스레드가 공유자원을 해제하면 세마포어에서 signal() 작업 수행
  • 조건 변수 없음, 프로세스나 스레드가 세마포어 값 수정할 때 다른 프로세스나 스레드 접근 불가

 

뮤텍스, 세마포어 차이점

  • 뮤텍스는 동기화 대상이 하나 ex) 사람(프로세스, 스레드), 화장실(공유 자원), 화장실 키(공유자원에 접근하기 위한 필요 오브젝트)
  • 세마포어는 동기화 대상이 여러개 ex) 사람(프로세스, 스레드), 화장실(공유자원), 화장실 빈칸 수(현재 공유자원에 접근 가능한 프로세스, 스레드 개수)

 

바이너리 세마포어

  • 0과 1만 갖는 세마포어
  • 구현상 뮤텍스와 유사
  • 뮤텍스: 잠금을 기반으로 상호배제가 일어나는 "잠금 메커니즘"
  • 세마포어: 신호를 기반으로 상호 배제가 일어나는 "신호 메커니즘"
  • ex) 노래 -> 전화 -> 노래 중지, 통화 처리 인터페이스

카운팅 세마포어

  • 다수의 값을 가질 수 있는 세마포어
  • 여러 자원에 대한 접근을 제어

 

모니터

  • 둘 이상의 스레드나 프로세스가 공유 자원에 안전하게 접근할 수 있도록 고유 자원을 숨기고, 해당 접근에 대해 인터페이스만 제공
  • 모니터 큐를 통해 공유 자원에 대한 작업들을 순차적으로 처리
  • 세마포어보다 구현 쉬움
  • 상호 배제는 자동 <-> 세마포어는 상호 배제를 명시적 구현해야 함

 

교착상태(Deadlock)

  • 2개 이상의 프로세스들이 서로가 가진 자원을 기다리며 중단된 상태
  • 프로세스 A와 프로세스 B가 각자의 점유하고 있는 자원들을 요청하며 대기하는 상황

교착 상태 원인

1. 상호배제

2. 점유 대기

3. 비선점

4. 환형 대기

 

1. 상호 배제

- 한 프로세스가 자원을 독점, 다른 프로세스들이 접근 불가능

 

2. 점유 대기

- 특정 프로세스가 점유한 자원을 다른 프로세스가 요청한 상태

 

3. 비선점

- 다른 프로세스의 자원을 강제적으로 가져올 수 없음

 

4. 환형 대기

- 2개의 프로세스가 서로가 서로의 자원을 요구하는 상황

 

 

교착상태 해결 방법

1. 자원 할당시, 교착상태 조건에 성립되지 않도록 설계

2. 교착 상태 가능성이 없을 때만 자원 할당 -> 은행원 알고리즘 사용

3. 교착 상태가 발생하면 사이클 유무 확인 -> 관련 프로세스를 1개씩 삭제

4. 교착 상태 처리 비용이 크기 때문에, 교착 상태가 발생하면 사용자가 작업을 종료( 현재 운영체제 채택 방법 )

ex) "응답 없음"

 

은행원 알고리즘

  • 총 자원의 양과 현재 할당한 자원의 양을 기준으로 안정 또는 불안정 상태로 나누고, 안정 상태로 가도록 자원을 할당하는 알고리즘
  • 프로세스당 요청할 자원들의 최대치를 통해 자원 할당 가능 여부 확인