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

2022. 7. 4. 18:01C#/운영체제

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

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

 

[운영체제] OS

[OS] 운영체제의 가장 주된 목적은 컴퓨터 하드웨어를 관리하는 것이다. 컴퓨터에는 수많은 하드웨어가 존재한다. CPU, 메모리, 키보드, 마우스 등이 있으며 이를 잘 관리해줘야 컴퓨터를 효율적

chlee200530.tistory.com

 

[Process]

실행되고 있는 프로그램을 뜻함. (메모리에 올라가 있는 상태)

메모리에는 여러 프로세스들이 할당되어 있고 이들은 동시에 실행되고 있다. 이를 OS 어떻게 동시에 실행시켜주고 관리해줄것인지등을 고민해야하고 이때 프로세스의 중요 data들을 담고 있는 PCB 통해 관리를 한다.

*PCB

PCB 프로세스에 대한 data 말한다. 상태, id, 다양한 레지스터, PC등이 저장 되어있다.

CPU에서는 이러한 프로세스들을 동시에 실행시킬  있도록 CPU 실행을 쪼개는 시분할을한다. (정확히는 동시에는 아니고 동시에 실행되고 있다고 느끼게끔) 이로 인해 실행되고 있던 P0 잠시 멈추고 Ready상태가 되고 P1 실행된다. 이렇게   있는 이유는 CPU연산이 매우 빨라서 유저가 느끼기엔 이렇게 쪼개면서 실행해도 연속으로 실행된다는 느낌을 받을  있고 OS 입장에선 한번에 여러 프로세스를 돌릴  있다.

  • 이러한 멀티프로그래밍을 통해 CPU의 사용률을 높일 수 있다.
  • 프로세스를 어떠한 기준으로 우선순위를 매길것인가를 해결하기 위해 스케쥴링이 존재한다.

이처럼 P0에서 P1 실행이 바뀔때 기존에 P0 PCB 저장해두고 다시 P0 실행될때 저장했던 PCB restore 하면 된다. 이러한 것을 Context switching 이라하고 대상은 PCB 된다.

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

*IPC

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

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

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

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

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

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

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

 

[스레드]

프로세스의 최소 실행 단위

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

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

  • CPU 자원 사용률을 높일 수 있다. -> 응답성이 좋아진다.

 멀티스레드는 기본적으로 하나의 프로세스안에 들어있고 공유자원이 있기 때문에 프로세스간 context switching보다 오버헤드가 적게 발생한다. 하지만 이렇게 공유자원에 여러 스레드가 동시에 접근했을  이미 다른 스레드에 의해 수정된 값을 불러오는등의 문제가 발생할  있다. 이를 위해 뮤텍스나 세마포어가 활용된다.

*동기화

뮤텍스 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알고리즘은 데드락이나 우선순위역전등의 문제점이 발생하지 않는다. 대신 라이브락이 발생할 수도...

https://bluemoon-1st.tistory.com/22

https://effectivesquid.tistory.com/62