[ STUDY ]/CS

[ 운영체제 ] 프로세스 2️⃣ - 프로세스 동기화, 교착 상태, IPC, 좀비고아···

김강니 2024. 11. 11. 05:07

1.2.7 프로세스 동기화

경쟁 상태

여러 프로세스 또는 스레드에서 하나의 공유자원에 동시에 접근하여 경쟁하는 상태

 

💡  너무 많은 우유 문제 - 프로세스 동기화가 필요하다!!

  1. 엄마가 냉장고에 우유 없는 걸 확인
  2. 엄마 우유 사러감
  3. 엄마 우유 사고 돌아오는 길에 아빠도 냉장고에 우유 없는 거 확인
  4. 아빠 우유 사러감
  5. 우유 2개 됨 -> 의도하지않은 결과 

 

임계 영역

공유 자원에 접근할 수 있고 접근 순서에 따라 결과가 달라지는 코드 영역

* 우유문제에서 냉장고에 우유가 있는지 없는지 판단하고 우유를 추가하는 부분이 이에 해당한다.

 

 

☝🏻 임계 영역에서 경쟁상태를 방지하기 위해 프로세스 동기화가 필요하다.

 

💡  임계 영역에 여러 접근이 동시에 발생하는 것을 방지하는 3가지 방법

  1. 상호 배제 기법(mutual exclusive)
    어떤 프로세스가 임계 영역을 실행 중일 때 다른 프로세스가 접근할 수 없게 한다.(뮤텍스, 세마포어)
    "한 방에 한 명만 들어간다"
  2. 진행(progress)
    임계 영역을 실행 중인 프로세스가 없을 때 다른 프로세스가 임계 영역을 실행한다.
    "방에 아무도 없으면 누군가 적극적으로 들어가야한다"
  3. 한정된 대기(bounded waiting)
    임계 영역에 접근을 요청했을 때 무한한 시간을 기다리지 않는다.
    "기다리고 있는 사람을 오래 기다리게 하지 않는다"

 

 

뮤텍스

뮤텍스는 락(lock)을 가진 프로세스만이 공유 자원에 접근할 수 있게 하는 방법

 

💡  화장실과 화장실 열쇠가 하나뿐인 식당

  1. A가 열쇠를 가지고 화장실에 간다.
  2. B는 열쇠가 없기 때문에 A가 화장실에 갔다가 돌아올 때까지 기다려야한다.
  3. A가 돌아오면 B는 열쇠를 가지고 화장실에 간다.

    여기서,
    화장실공유 자원을 포함한 임계 영역
    열쇠
    A와 B공유 자원에 접근하려는 프로세스

☝🏻 임계 영역에 접근한 프로세스가 임계영역에 락을 건다고 해서 락킹 매커니즘이라고도 한다.

 

💡  바쁜 대기
임계 영역에 접근하려고 기다리는 프로세스가 공유자원에 접근할 수 있는 권한을 얻을 때까지 확인하는 과정
* 스핀락 : 바쁜 대기의 한 종류로 락이 풀렸는지 반복문을 돌면서 확인하는 것

 

 

 

세마포어

공유 자원에 접근할 수 있는 프로세스의 수를 정해 접근을 제어한다.

* 뮤텍스와 동일하지만 접근할 수 있는 프로세스가 여러개이다. 즉, 화장실이 3개, 열쇠도 3개임.

 

☝🏻 공유 자원에 접근한 프로세스가 접근을 해제하면 다른 프로세스에 신호를 보낸다고 해서 시그널링 메커니즘이라고도 한다.

 

⏬ 동기, 비동기, 블로킹, 넌블로킹 비교

더보기

동기 🆚 비동기

여러 작업을 처리할 때,

동기 : 작업 순서를 보장한다.

비동기 : 작업 순서를 보장하지 않는다.

블로킹 🆚 넌블로킹

작업을 수행할 때,

블로킹 : 대기할 수 있다. 작업 순서를 보장하지 않는다

넌블로킹 : 대기없이 수행한다.

 

 

1.2.8 교착 상태(deadlock, 데드락) ⭐️⭐️⭐️

2개 이상의 프로세스가 각각 자원을 가지고 있으면서 서로의 자원을 요구하며 기다리는 상태

 

💡  교착상태가 발생하는 4가지 필요 충분 조건

  1. 상호배제(mutual exclusion)
    하나의 공유 자원에 하나의 프로세스만 접근할 수 있다.
    "화장실은 한 번에 한 사람만 사용 가능!"

  2. 점유와 대기(hold and wait)
    프로세스가 최소 하나의 자원을 점유하고 있는 상태에서 추가로 다른 프로세스에서 사용중인 자원을 점유하기 위해 대기한다.
    "A가 화장실을 쓰고 있으면서, B가 쓰는 드라이기도 달라고 요청" - A는 B가 쓰는 드라이기를, B는 A가 쓰는 화장실을 기다림

  3. 비선점(non-preemption)
    다른 프로세스에 할당된 자원을 뺏을 수 없다
    "누군가 화장실을 쓰고 있으면 강제로 문을 열고 들어갈 수 없다"

  4. 환형 대기(circular wait)
    프로세스가 자신의 자원을 점유하면서 앞이나 뒤에 있는 프로세스의 자원을 요구한다.
    "세사람이 원형으로 서로의 물건을 달라고 요청하면서 기다린다." - 세사람 모두 원하는 물건을 먼저 받아야 내 물건을 줄 수 있음
    즉, 프로세스는 다음 자원을 받기 전까지 자신이 가진 자원을 반환하지 않는다.

 

☝🏻 교착상태를 막으려면 이 4가지 필요 충분 조건중에 한 가지를 제거하면 된다.

    1. 상호배제 부정
      여러 프로세스가 동시에 하나의 공유 자원을 사용할 수 있도록 한다.
      "화장실 안에 🚽를 여러개 만들어서 여러 명이 사용할 수 있도록"

    2. 점유와 대기 부정
      프로세스가 실행되기 전에 필요한 모든 자원을 할당 -> 프로세스 대기를 없앤다
      프로세스가 자원을 점유하지 않은 상태에서만 자원을 요구
      "A에게 처음부터 화장실과 드라이기를 준다" or "A가 화장실을 사용하지 않을 때만 드라이기를 요구한다"

    3. 비선점 부정
      자원을 점유한 프로세스가 다른 자원을 요구할 때 점유하고 있는 자원을 반납한다.
      "A가 화장실을 쓰고 있으면서 드라이기를 요구한다면, A는 화장실을 먼저 비워야 드라이기를 요청할 수 있다"

    4. 환형 대기 부정
      자원을 선형 순서로 정렬해 고유 번호를 할당한다. 그리고 각 프로세스에서 요구할 수 있는 번호의 방향을 정해서 한쪽 방향으로만 자원을 요구한다.
      "화장실(1번), 드라이기(2번) : 1번을 먼저 요청해야만 2번을 요청할 수 있다."

 

 

1.2.9 스레드 안전

스레드 안전이란 하나의 변수, 함수, 객체에 스레드 여러개가 동시에 접근해도 문제가 없음을 의미한다.

* 스레드 안전하지 않은 경우 스레드끼리 데이터 값을 덮어쓰기가 일어날 수 있다.

 

💡  스레드 안전을 위한 조건

  1. 상호배제(mutual exclusion)
    뮤텍스 또는 세마포어와 같은 상호배제 기법을 사용해 접근을 통제해야한다.
    "화장실은 한 번에 한 명만 사용하도록 잠금장치를 건다"
  2. 원자 연산(atomic operation)
    공유 자원에 접근할 때 원자 연산(연산했다, 연산 안했다)을 이용한다.
    "100원 인출 버튼을 눌렀을 때 100원이 인출될 때까지 다른 사람이 개입 못함"

  3. 재진입성(reentrancy)
    특정 함수를 하나의 스레드에서 실행 중일 때 다른 스레드가 해당 함수를 실행해도 각 스레드에 올바른 결과가 나올 수 있게 한다.
    "한 개의 시험 문제를 각자 자신의 노트에 푼다" -> 충돌 방지

  4. 스레드 지역 저장소(thread local storage)
    각 스레드에서만 접근할 수 있는 저장소를 사용해서 공유되는 자원을 줄인다.
    "필요한 물건을 자기 서랍에 보관하고 사용"

 

 

1.2.10 IPC

IPC는 프로세스가 자원을 공유하는 방식이다.

* 프로세스는 고유한 메모리 영역을 가지기 때문에 프로세스간에 자원을 공유해야 할 때가 있다. 

 

💡  IPC 종류

  1. 공유 메모리(shared memory)
    프로세스간 공유 가능한 메모리를 구성해 자원을 공유한다.
    여러 프로세스에서 접근할 때 동기화 문제가 발생할 수 있다.
    "같은 노트를 공유해서 데이터를 쓰고 읽는다"

  2. 소켓(socket)
    네트워크 소켓을 이용하는 프로세스 간 통신으로, 외부 시스템과도 이용할 수 있다.
    클라이언트 <-> 서버 구조로 자원을 주고받는다.
    "클라이언트가 편지를 보내고 서버가 우체통 역할을 한다."

  3. 세마포어(semaphore)
    접근하는 프로세스를 제어 -> 화장실 키 만들어
    "화장실 키 만들어"

  4. 파이프(pipe)
    FIFO형태의 메모리인 파이프를 이용해서 프로세스 간 자원을 공유
    단방향 통신만 지원하므로 읽기 또는 쓰기 중 하나만 할 수 있음. 양방향 통신하려면 읽기파이프 쓰기파이프 생성해야함
    "한 쪽 프로세스는 데이터를 읽기만하고, 한 쪽은 쓰기만 함" - 단방향 통신
    "A는 1번 벨트에 요청을 보내고 B는 2번 벨트에 요청을 보냄, A는 2번 벨트에서 요청을 받고 B는 1번 벨트에서 요청을 받음" - 양방향 통신

  5. 메시지 큐(message queue)
    FIFO형태의 큐 자료구조를 사용해서 프로세스 간 메시지를 주고받는다. - 우선순위로 각자 맞게끔 가져가게 함
    "여러 사람이 편지(메시지)를 우체통에 넣고 필요한 사람이 순서대로 편지를 가져감"

 

 

1.2.11 좀비 프로세스와 고아 프로세스

💡  좀비 프로세스

자식 프로세스가 종료되었는데 부모 프로세스가 자식 프로세스의 종료 상태를 회수하지 않았을 경우 남겨진 자식 프로세스

  1. 자식 프로세스가 종료 -> 부모에 SIGCHLD 시그널 보냄
  2. 부모 프로세스는 wait() 함수(시스템 콜)을 호출해 자식 프로세스의 상태 정보를 받고 자원을 회수
  3. 이때, 자원 회수에 실패하면 자녀는 좀비가 됨....
    좀비 프로세스가 쌓이면 자원이 낭비됨


💡  고아 프로세스

자식 프로세스보다 부모 프로세스가 먼저 종료되는 경우 -> 종료했을 때 자원을 회수해줄 부모가 없음

이럴 때 자식 프로세스의 부모 PID를 1(init프로세스)로 바꾸고 종료됐을 때 init프로세스가 고아의 자원을 회수해준다.

-> 좀비 프로세스 방지