프로세스
: 컴퓨터에서 연속적으로 실행되고 있는 프로그램
동적인 개념으로는 실행된 프로그램을 의미
디스크로부터 메모리에 적재되어 CPU의 할당을 받을 수 있는 것
메모리에 올라와 실행되고 있는 프로그램의 인스턴스 (독립적인 개체)
운영체제로부터 시스템 자원(주소공간, 파일, 메모리 등)을 할당받는 작업의 단위
프로그램과 프로세스는 다르다.
프로그램은 명령어를 내용으로 가진 디스크에 저장된 파일. 즉 수동적인 존재(Passive entity)
프로세스는 다음에 실행할 명령어를 지정하는 프로그램 카운터 및 관련된 자원의 집합을 가진 능동적 존재(active entity)
특징
: 프로세스는 각각의 독립적인 메모리 영역(Code, Data, Stack, Heap의 구조)를 할당
Code: 프로그램을 실행시키는 실행 파일 내의 명령어(소스코드)
Data: 전역변수, Static변수의 할당
Heap: 동적 할당을 위한 메모리 영역
Stack: 지역변수, 함수 호출 시 전달되는 파라미터를 위한 메모리 영역
Stack
: 지역변수, 매개변수, 복귀 번지 등이 저장되어 있는 프로그램이 자동으로 사용하는 임시 메모리 함수 호출 시 생성되고, 함수 종료시 반환됨 (LIFO)
Heap
: 프로그래머가 동적으로 사용하는 영역
malloc, free 또는 new, delete에 의하여 할당 또는 반환되는 영역.
garbage collector가 활동하는 경우 자동으로 반환되는 경우도 있음
Data
: 전역변수(global), 정적변수(Static), 배열(Array), 구조체(Structure)등이 저장됨
1) 초기화 된 데이터: data에 저장
2) 초기화 되지 않은 데이터 : bss(Block Stated Symbol)에 저장
=> data 영역이 런타임 이전에 초기화 하는 것이라면 bss는 런타임 이후 초기화 하는 것
각 프로세스는 별도의 주소 공간에서 실행, 한 프로세스는 다른 프로세스의 변수나 자료구조에 접근X
한 프로세스가 다른 프로세스의 자원에 접근하려면 프로세스 간의 통신(IPC, Inter-Process Communication)을 사용
스레드(thread)
: 한 프로세스 내에서 실행되는 여러 흐름의 단위
프로세스의 특정한 수행경로
프로세스가 할당받은 자원을 이용하는 실행의 단위, CPU 이용의 기본 단위
프로세스 내의 주소 공간이나 자원을 공유
스레드 ID, 프로그램 카운터(PC), 레지스터 집합, 스택으로 구성
같은 프로세스에 속한 다른 스레드와 코드, 데이터 섹션, 열린 파일이나 신호와 같은 운영체제 자원을 공유
하나의 프로세스를 다수의 실행 단위로 구분하여 자원을 공유하고 자원의 생성과 관리의 중복성을 최소화하여 수행 능력을 향상하는 것
=> 멀티스레딩
각각의 스레드는 독립적인 작업을 수행해야 하기 때문에 각각의 스택과 PC 레지스터를 가짐
특징
스레드는 프로세스 내에서 각각 Stack과 레지스터를 따로 할당받고 Code, Data, Heap 영역은 공유
한 스레드가 프로세스 자원을 변경하면, 다른 이웃 스레드(Sibling Thread)도 그 변경 결과를 즉시 확인 가능
분류
: 권한이 없는 스레드가 시스템 호출을 이용할 수 없도록 막기 위해 종류를 나눔
스택을 스레드마다 독립적으로 할당하는 이유?
: 스택은 함수 호출 시 전달되는 인자, 되돌아갈 주소 값 및 함수 내에서 선언하는 변수등을 저장하기 위해 사용되는 메모리 공간.
스택 메모리 공간이 독립적이라는 것은 독립적인 함수 호출이 가능하다는 것
=> 독립적인 실행 흐름의 추가
PC 레지스터를 스레드마다 독립적으로 할당하는 이유?
: PC 값은 스레드가 명령어의 어디까지 수행했는지를 나타낸다.
스레드는 CPU를 할당 받았다가 스케줄러에 의해 다시 선점 당하는데, 이 때문에 명령어가 연속적으로 수행되지 못하고 어느 부분까지 수행됐는지 기록을 해야한다.
스레드 풀(Thread Pools)
: 웹 서버는 요청을 받을 때마다 요청을 위해 새로운 스레드를 생성
프로세스를 시작할 때, 일정한 수의 스레드를 미리 풀로 만들어 두는 것
평소에는 기다리다가 요청이 들어오면 풀의 한 스레드에게 서비스 요청을 할당
요청이 끝나면 스레드는 다시 풀로 돌아가 다음 작업을 대기
다중 스레드 서버의 문제점
1) 서비스 할 때마다 스레드를 생성하는데 시간이 소요
2) 모든 요청마다 새로운 스레드를 만들어 서비스를 한다면 동시에 실행할 수 있는 최대 스레드의 한계를 정해야함
장점
새 스레드를 만들어 주는 것 보다 기존 스레드로 서비스 하는 것이 더 빠름
스레드 풀은 임의 시각에 존재할 수 있는 스레드 개수에 제한. 많은 수의 스레드를 병렬 처리 할 수 없는 시스템에 도움
왜 멀티 프로세스 대신 멀티 스레드를 사용할까?
: 프로그램을 여러 개 켜는 것보다 하나의 프로그램에서 여러 작업을 하는 것
1. 응답성(Responsiveness) 증가
프로그램 일부분이 봉쇄되거나, 긴 작업을 실행하더라도 프로그램의 실행이 계속되는 것을 허용함으로써 사용자에 대한 응답성을 증가.
ex) 웹 브라우저는 한 스레드가 이미지 파일을 로드하고 있는 동안 다른 스레드에서 사용자와의 상호작용
2. 자원 공유(Resource Sharing) : 자원의 효율성 증가
프로세스를 생성하여 자원을 할당하는 시스템 콜이 줄어들어 자원을 효율적으로 관리 가능
스레드는 프로세스 내의 메모리를 공유하기 때문에 독립적인 프로세스와 달리 스레드 간의 데이터를 주고 받는 것이 간단해지고 시스템 자원 소모가 감소
코드와 데이터를 공유하면 한 응용 프로그램이 같은 주소 공간 내에 여러 개의 다른 작업을 하는 스레드 보유 가능
3. 경제성(Economy) : 처리 비용 감소
프로세스 간의 통신(IPC)보다 스레드 간의 통신 비용이 적어 작업들 간의 통신 부담이 감소
프로세스 생성을 위해 메모리와 자원을 할당하는 것보다 스레드를 생성하고 문맥 교환을 하는 것이 더 경제적
프로세스 간의 전환 속도보다 스레드 간의 전환 속도가 더 빠름
스레드가 프로세스보다 경량이기 때문에 생성과 제거가 쉽다.
4. 규모 가변성(Scalability)
멀티 스레드에서 주의할 점
동기화 문제
스레드 간의 자원 공유는 전역 변수(데이터 세그먼트)를 이용하므로 함께 사용시 충돌 발생 가능
사용중인 변수나 자료구조에 접근하여 잘못된 값을 읽어오거나 수정할 수 있다.
동기화를 통해 작업 처리 순서를 컨트롤하고 공유 자원에 대한 접근을 컨트롤 해야함
멀티 스레드는 적은 공간을 차지하고 Context Switching이 빠르다는 장점을 가지고 있지만 오류로 인해 하나의 스레드가 종료될 때 전체 스레드가 종료될 수 있다.
Context
: CPU가 해당 프로세스를 실행하기 위한 해당 프로세스들의 정보
프로세스의 PCB에 저장한다
Context Switching
: 현재 진행하고 있는 Task(Process, Thread)의 상태를 저장하고 다음 진행할 상태의 Task의 저장된 상태 값을 읽어 복구하는 작업
Context Switching을 하는 이유
하나의 Task만 처리할 수 있다면?
동시에 사용하는 것 처럼 하기 위해
Task의 대부분 정보는 Register에 저장되고 PCB(Process Control Block)로 관리
현재 실행되고 있는 Task의 PCB 정보를 저장(Process Stack, Ready Queue)
다음 실행할 Task의 PCB 정보를 읽어 Register에 적재하고 CPU가 이전에 진행했던 과정을 연속적으로 수행
Context Switching Cost
많은 cost가 필요
Process VS Thread
Process Context Switching Cost > Thread Context Switching Cost
Thread는 Stack 영역을 제외한 모든 메모리를 공유하기 때문에 Context Switching 수행 시 Stack 영역만 변경하면 되기 때문에 비용이 적다.
Thread-Safe
: 멀티스레드 환경에서 여러 스레드가 동시에 하나의 객체 및 변수(공유 자원)에 접근할 때, 의도한 대로 동작하는 것
구현하기
공유 자원에 접근하는 임계 영역(Critical Section)을 동기화 기법으로 제어해야 한다.
동기화 기법으로는 Mutex나 Semaphore가 존재
예를 들어 정적(전역)변수를 사용하거나 반환하면 안되고 호출 시 제공된 매개 변수만으로 동작해야함.
=> 따라서 ReEntrant하면 Thread-Safe하지만 역은 성립되지 않는다.
유저 모드 동기화
커널의 힘을 빌리지 않는 (커널 모드가 실행되지 않는) 동기화 기법
성능상 이점, 기능상의 제한
ex) 크리티컬 섹션 기반의 동기화, 인터락 함수 기반의 동기화
커널 모드 동기화
커널에서 제공하는 동기화 기능을 활용하는 방법
커널 모드로의 변경이 필요 -> 성능 저하
다양한 기능 활용 가능
ex) 뮤텍스 기반의 동기화, 세마포어 기반의 동기화, 이벤트 기반의 동기화
경쟁상황(Race Condition)
: 동시에 여러 개의 프로세스가 동일한 자료를 접근하여 조작하고, 그 실행 결과가 접근이 발생한 특정 순서에 의존하는 상황
임계 영역(Critical Section)
: 동일한 자원을 동시에 접근하는 작업을 실행하는 코드 영역
임계 영역 문제(Critical Section Problem)
: 프로세스들이 Critical Section을 함께 사용할 수 있는 프로토콜을 설계하는 것
해결을 위한 기본 조건
Mutual Exclusion(상호배제)
: 프로세스 1이 임계 영역에서 실행중이라면 다른 프로세스들은 그들이 가진 임계 영역에서 실행될 수 X
Progress(진행)
: 임계 영역에서 실행 중인 프로세스가 없고 별도의 동작이 없는 프로세스들만 임계 영역 후보로서 참여 가능
Bounded Waiting(한정된 대기)
: 프로세스 1이 임계 영역 진입 신청 후 받아들여질 때까지 다른 프로세스들이 임계 영역에 진입하는 횟수는 제한이 있어야함
해결책
뮤텍스(Mutex)
공유된 자원의 데이터를 여러 프로세스나 스레드가 접근하는 것을 막는 것
상호 배제(Mutual Exclusion)라고도 함
Critical Section을 가진 스레드의 Running Time이 겹치지 않도록 각각 단독으로 실행하게 하는 기술
다중 프로세스들이 공유 리소스에 대한 접근을 조율하기 위해 Syncronized 또는 lock을 사용
세마포어(Semaphore)
공유된 자원의 데이터를 여러 프로세스나 스레드가 접근하는 것을 막는 것
리소스 상태를 나타내는 간단한 카운터로 생각
운영체제 또는 커널의 한 지정된 저장장치 내의 값
일반적으로 비교적 긴 시간을 확보하려는 리소스에 사용
유닉스 시스템 프로그래밍에서 세마포어는 운영체제의 리소스를 경쟁적으로 사용하는 다중 프로세스에 행동을 조정하거나 동기화 시키는 기술
공유 리소스에 접근할 수 있는 프로세스의 최대 허용치만큼 동시에 사용자가 접근하여 사용 가능
각 프로세스는 세마포어 값을 확인하고 변경 가능
사용중이지 않은 자원의 경우 그 프로세스가 즉시 자원을 사용
이미 다른 프로세스에 의해 사용중이라는 사실을 알게 되면 재시도하기 전에 일정 시간을 대기
세마포어를 사용하는 프로세스는 그 값을 확인하고, 자원을 사용하는 동안에는 그 값을 변경함으로써 다른 세마포어 사용자들이 기다리도록 함.
세마포어는 2진수를 사용하거나 추가적인 값을 가질 수 있음
카운팅 세마포어
: 가용한 개수를 가진 자원에 대한 접근 제어용으로 사용, 세마포어는 가용한 자원의 개수로 초기화.
자원을 사용하면 감소, 방출하면 증가
이진 세마포어
: Mutex 라고도 부르며 상호 배제의 머리 글자를 따서 만들어짐. 이름 그대로 0과 1 사이의 값만 가능하며 다중 프로세스들 사이의 임계 영역 문제를 해결하기 위해 사용
세마포어와 뮤텍스의 차이
가장 큰 차이는 관리하는 동기화 대상의 개수
Semaphore는 Mutex가 될 수 있지만 Mutex는 Semaphore가 될 수 없음
Semaphore는 소유할 수 없는 반면, Mutex는 소유 가능. 소유주가 이에 대한 책임을 가짐
Mutex의 경우 Mutex를 소유하고 있는 thread가 Mutex를 해제 할 수 있지만 Semaphore는 Semaphore를 소유하지 않는 스레드가 해제 가능
Semaphore는 시스템 범위에 걸쳐 있고 파일 시스템 상의 형태로 존재하지만 Mutex는 프로세스 범위를 가지며 프로세스가 종료될 때 자동으로 Clean up
교착상태의 4가지 조건
1. 상호 배제 (Mutual Exclusion)
한 번에 한 프로세스만 공유 자원을 사용
좀 더 정확하게는 공유 자원에 대한 접근이 제한
자원의 양이 제한되어 있더라도 교착상태는 발생 가능
2. 점유대기 (Hold and Wait)
3. 비선점 (Preemtive)
4. 순환대기(Circular wait)
=> 4가지 조건을 다 만족해야 교착상태