[운영체제] 프로세스와 쓰레드

2024. 12. 12. 20:09STUDY/운영체제

728x90
반응형

이 글은 '쉽게 배우는 운영체제' 서적을 바탕으로 작성되었습니다.

지난 포스팅에서 운영체제에 대해 공부했었다. 이어서 보면 좋을거같다

https://chlee200530.tistory.com/147?category=1073541 

[Process]

프로세스의 정의

프로그램은 저장장치에 저장되어 있는 정적인 상태이고, 프로세스는 실행을 위해 메모리에 올라온 동적인 상태를 말한다.

오늘날 운영체제는 대부분 시분할 방식을 사용하고 있기 때문에 프로세스가 여러 상태(프로세스 상태)를 오가며 실행된다. 운영체제가 여러 프로세스를 실행하기 위한 주문서 즉 프로세스 제어 블록(PCB)를 통해 프로세스간 문맥 교환을 이룬다.

결론적으로 어떤 프로그램이 프로세스가 되었다는 것은 운영체제로부터 프로세스 제어 블록을 받았다는 의미이다. 

 

프로세스의 상태

상태 설명 작업
생성 프로그램을 메모리에 가져와 실행 준비가 완료된 상태이다. 메모리 할당, PCB 생성
준비 실행을 기다리는 모든 프로세스가 자기 차례를 기다리는 상태이다.
실행될 프로세스를 CPU 스케줄러가 선택한다.
dispatch(PID) : 준비 → 실행
실행 선택된 프로세스가 타임 슬라이스를 얻어 CPU를 사용하는 상태이다. 
프로세스사이에 문맥 교환이 일어난다.
timeout(PID) : 실행 → 준비
exit(PID) : 실행 →  완료
block(PID) : 실행 → 대기 
대기 실행 상태에 있는 프로세스가 입출력을 요청하면 입출력이 완료될 때까지 기다리는 상태이다. 입출력이 완료되면 준비 상태로 간다. wakeup(PID) : 대기 → 준비
완료 프로세스가 종료된 상태이다. 사용하던 모든 데이터가 정리된다.  메모리 삭제, PCB 삭제

대부분의 프로세스는 생성, 준비, 실행, 대기, 완료 상태로 운영되며 이 다섯 가지 상태를 활성 상태(active status)라고 한다. 프로세스의 상태는 활성 상태 외에 또 다른 상태가 있는데 여기서 설명하는 상태는 조금 특별한 경우이다.

 

휴식 상태

프로세스가 작업을 일시적으로 쉬고 있는 상태이다. 휴식 상태에서는 사용하던 데이터가 메모리에 그대로 있고 PCB도 유지되므로 프로세스는 멈춘 지점에서부터 재시작(resume)할 수있다.

보류 상태

보류 상태는 프로세스가 메모리에서 잠시 쫓겨난 상태로 휴식 상태와 차이가 있다. 보류 상태는 '일시 정지 상태'라고도 불리며 보류 상태와 비교하여 일반적인 프로세스 상태를 활성 상태라고 한다. 프로세스는 다음과 같은 경우에 보류 상태가 된다.

  • 메모리가 꽉차서 일부프로세스를 메모리 밖으로 내보낼 때
  • 프로그램에 오류가 있어서 실행을 미루어야 할 때
  • 바이러스와 같이 악의적인 공격을 하는 프로세스라고 판단될 때

이러한 경우 외에도 여러 가지 이유로 프로세스가 보류 상태에 들어가는데, 대부분이 컴퓨터의 성능을 떨어뜨리거나 실행을 미루어도 큰 지정이 없는 프로세스이다.

 

프로세스 제어 블록(PCB)

PCB는 프로세스를 실행하는데 필요한 중요한 정보를 보관하는 자료 구조이다.

모든 프로세스는 고유의 PCB를 가지며, PCB는 프로세스 생성 시 만들어져서 프로세스가 실행을 완료하면 폐기된다.

  • 포인터 : 준비 상태나 대기상태는 큐로 운영하는데, PCB를 연결하여 준비 상태나 대기 상태로의 큐로 구현할 때 포인터가 사용된다.
  • 프로세스 상태 : 위에서 말한 프로세스 상태를 말한다. 현재 어떤 상태인지를 나타낸다.
  • 프로세스 구분자(PID) : 운영체제 내에 있는 여러 프로세스를 구별하기 위한 구분자 (ID) 역할을 한다.
  • 프로그램 카운터(PC) : 다음에 실행될 명령어의 위치를 가리키는 PC 값을 저장한다.
  • 프로세스 우선순위 : 프로세스의 중요도를 의미하며 CPU 스케줄러가 준비 상태에 있는 프로세스 중 실행 상태로 옮겨야 할 프로세스를 선택할 때는 프로세스 우선순위를 기준으로 삼는다.
  • 각종 레지스터 정보 : 프로세스가 실행되는 중에 사용하던 각종 레지스터가 저장된다. 
  • 메모리 관리 정보 : 메모리 위치 정보, 메모리 보호를 위한 경계 및 한계 레지스터 값이 저장된다.그 외에 세그먼테이션 테이블, 페이지 테이블등의 정보도 보관된다. 
  • 할당된 자원 정보 : 프로세스를 실행하기 위해 사용하는 입출력 자원이나 오픈 파일등에 대한 정보를 말한다.
  • 계정 정보 : 계정 번호, CPU 할당 시간, CPU 사용 시간 등의 정보를 저장한다.
  • PPID와 CPID : PCB간 부모-자식 관계를 나타낸다.

 

문맥 교환(context switching)

문맥 교환은 CPU를 차지하던 프로세스가 나가고 새로운 프로세스를 받아들이는 작업을 말한다. 실행 상태에서 나가는 PCB에는 지그까지의 작업 내용을 저장하고 반대로 실행 상태로 들어오는 PCB의 내용에는 CPU가 다시 세팅된다.

이와 같이 두 프로세스의 PCB을 교환하는 작업을 문맥 교환이라고 한다.

문맥 교환이 일어나는 경우는 매우 다양하다. 일반적으로 한 프로세스가 자신에게 주어진 시간을 다 사용하면 발생하고, 인터럽트가 걸렸을 때도 발생한다.

 

*IPC

프로세스는 서로가 독립된 실행객체다. 그만큼 별도의 무언가가 없으면 서로간의 통신이 어렵다는 뜻이다. 이때문에 프로세스간 통신을 원활하게 돕기 위해 커널에서 IPC(Inter-Process Communication) 제공한다. 

PIPE : 부모자식간 단방향 통신 방법이다.  그대로  프로세스 사이에 가상의 PIPE 만드는 것이다.

  1. 양방향으로 통신하고 싶으면 pipe 하나더 만들면 된다
  2. 꼭 부모자식 관계가 아닐때 pipe를 쓸 수 있도록 named pipe가 존재한다.

Shared Memory :  그대로 메모리 공간을 공유하는 방법이다.

  1. 빠르게 리소스를 가져올 수 있는 장점이 있는 반면, 보안적인 측면에서 취약할 수 있다.

Memory Map : 오픈된 파일에 한해서 메모리를 공유하는 방법이다파일을 오픈하면 해당 파일의 데이터가 메모리에 올라가는데 똑같은 파일을 오픈할 경우 이미 올려지니 메모리 공간에 같이 접근해서 데이터를 읽고 쓰는 방식이다.

  1. windows에서는 같은 파일을 오픈하면 count를 1증가시켜 몇개의 파일이 열렸나를 체크하기도 한다.

Socket : 소켓 통신은 흔히 네트워크 통신 기법으로 많이 사용되며 데이터 교환을 위해 양쪽 PC에서 각각 임의의 포트를 정하고 해당 포트 간의 대화를 통해 데이터를 주고 받는 방식이다.

 

[스레드]

프로세스의 작업 과정을 자세히 살펴보자. 운영체제는 코드와 데이터를 메모리에 가져오고, PCB를 생성하고 메모리 영역을 할당한 후 준비된 프로세스를 준비 큐에 삽입한다. 프로세스가 생성되면 CPU 스케줄러는 프로세스가 해야할 일을 CPU에 전달하고 실제 작업은 CPU가 수행한다. 이때 CPU 스케줄러가 CPU에 전달하는 일 하나가 스레드다.

즉, 프로레스의 코드에 정의된 정차에 따라 CPU에 작업 요청을 하는 실행 단위이다.

멀티스레드를  사용하는가?

싱글스레드를 사용할 경우 해당 스레드가 연산량이 많아  작업을 요구할때 사용자의 또다른 요청에 대한 응답을 하지 못한다. 하지만 멀티스레드는 다른 스레드에서 또다른 작업을 수행할  있다.

즉 CPU 자원 사용률을 높일 수 있다는 말이며, 이는곧 응답성이 좋아진다는 의미이다.

멀티스레드의 단점

우리가 자주 사용하는 브라우저들인 인터넷 익스플로러와 구글 크롬을 생각해보자.

두 브라우저는 멀티탭 기능을 이용하여 여러 개의 화면을 띄울 수 있는데, 익스플로러는 하나의 프로세스에 멀티스레드를 사용하고 크롬은 여러개의 프로세스를 사용한다. 여러개의 프로세스를 사용하는데에는 문맥 교환과 같은 낭비 요소가 있어서 멀티스레드를 사용한다고 하지만, 여기에도 단점이 존재한다.

멀티 스레드를 사용하는 익스플로러는 여러 화면을 동시에 띄웠는데 그중 하나에 문제가 생겨 강제 종료를 하면 그 화면만 사라지는 것이 아니라 익스플로러 전체가 종료된다. 그러나 크롬은 독립적인 프로세스이므로 그중 하나가 문제가 생겨 종료해도 다른 화면에 미치는 영향이 적다. 즉 멀티스레드를 사용해서 하나의 스레드에 문제가 생기면 다른 스레드 혹은 프로세스 전체에 영향을 미치게 된다는 단점이 존재한다.

이를 위해 뮤텍스나 세마포어가 활용된다.

동기화

뮤텍스 vs 세마포어

  • 뮤텍스의 경우 여러 스레드(혹은 프로세스) 공유자원을 쓰려고 할때 이를 크리티컬 섹션으로 만들고 하나의 스레드에서만 사용할  있도록 lock 거는 방식이다. 해당 스레드가 작업을 완료하고 unlock상태가 될때까지 다른 스레드는 대기한다.
  • 세마포어의 경우 세마포어 변수를 만들어 해당 변수만큼 공유자원에 접근할  있도록 한다. 만약 변수가 1이라면 '바이너리 세마포어'라하며 뮤텍스와 동일하게 동작한다. wait() signal() 통해 변수를 감소, 증가 시킬  있다.

*Busy waiting

OS에서 원하는 자원을 얻기 위해 기다리는 것이 아니라 권한을 얻을 때까지 확인하는 것을 의미한다. 뮤텍스와 세마포어를 구현했을때 크리티컬섹션에 진입하기 위해 무한루프를 돌며 대기해야하는 현상 발생하는데 이를 Busy waiting이라 한다. 그래서 뮤텍스 lock spinlock이라고도 한다

  • busy waiting은 어떤 상황일때 사용하는게 좋을까?

자원의 권한을 얻는데 많은 시간이 소요되지 않는 상황인 경우와 context switchig비용보다 기다리는게 성능적으로 우수할 경우 사용하는게 좋다.

*lock기반 알고리즘의 단점

Lock 확보하지 못한 스레드는 실행되지 못하고 lock 확득한 스레드가 lock release할때까지 대기 상태에 머물러야 하며 조건이 출족 될때 다시 실행시켜야한다. 여기서 끝인가 lock 획득하더라도 실제 CPU 할당 받기 전에 이미 CPU 사용하고 있는 다른 스레드가 CPU할당량을 모두 사용하고 CPU 스케줄을 넘겨줄  까지 대기해야한다. , lock 대한 경쟁이 심해질 수록 실제로 필요한 작업을 처리하는 시간 대비 동기화작업에 필요한 시간의 비율이 높아지면서 성능이 떨어지게 된다.

*CAS(compare-and-set)

CAS연산에는 3개의 인자를 넘겨준다.

-> 작업할 대상 메모리의 위치(V), 기존 (A), 새로 설정할 (B).

CAS연산은 V위치에 있는 값이 A 같은 경우 B 변경하는 단일 연산이다. 만약 이전 값이 A 다르다면 아무런 동작도 하지 않는다. 그리고 값을 B 변경했던 못했건 어떤 경우라도 현재 V 값을 리턴한다. 만약 여러 스레드가 동시에 CAS연산을 통해 변수의 값을 변경하려고 한다면 하나의 스레드는 성공적으로 값을 변경할 것이고 나머지는 모두 실패할 것이다. 대신 값을 변경하지 못했다고해서 lock 확보하는 것처럼 대기 상태에 들어가는 다시 시도할  있다고 알림을 받는 이다.

 

*lock-free알고리즘

lock기반으로 동작하는 알고리즘의 경우 lock 확보하고 있는 스레드가 I/O작업 때문에 대기 중이거나 기타 어떤 원인 때문에라도 대기 상태에 들어간다면 lock 획득하기 위해 대기하고 있는 다른 스레드가 전부 대기 상태에 들어갈 가능성이 있다. 특정 스레드에서 작업을 실패하거나 또는 대기 상태에 들어가는 경우에, 다른 어떤 스레드라도 그로인해 실패하거나 대기 상태에 들어가지 않는 알고리즘을 Non-Blocking알고리즘이라고  작업 단계마다 일부 스레드는 항상 작업을 진행할  있는 경우 lock-free알고리즘이라고 한다.

여러 스레드가 경쟁하지 않는 상황이라면 CAS연산은 항상 성공하고 여러 스레드가 경쟁을 한다고해도 최소한 하나의 스레드는 반드시 성공하기 때문에 성공한 스레드는 작업을 진행할  있다. Non-Blocking알고리즘은 데드락이나 우선순위역전등의 문제점이 발생하지 않는다. 대신 라이브락이 발생할 수도...

 

TODO : 프로세스 동기화, 멀티 스레드 모델

 

728x90
반응형