[CS] 2.프로세스-3

D.O·2024년 3월 27일
0

경쟁 상태

여러 프로세스 또는 스레드에서 하나의 공유 자원에 접근하는 경우가 있는데, 이때 자원에 접근하는 순서에 따라 결과 값이 달라질 수 있다. 이러한 현상을 공유 자원에 동시에 접근해 경쟁하는 상태라고 해서 경쟁 상태(race condition)라고 한다.

경쟁 상태의 발생 원인

  1. 동시성(Concurrency): 멀티 스레딩 또는 멀티 프로세싱 환경에서 공유 자원에 동시에 접근하려는 경우 발생합니다.
  2. 자원 공유: 여러 프로세스 또는 스레드가 같은 메모리 공간, 파일, 데이터베이스 등의 자원을 공유할 때 발생할 수 있습니다.
  3. 순서의 불확정성: 프로세스 또는 스레드의 실행 순서가 운영 체제의 스케줄링 알고리즘에 의해 결정되므로, 개발자가 이 순서를 예측하거나 제어하기 어렵습니다.

임계영역

임계 영역(Critical Section)이란 여러 프로세스나 스레드가 동시에 실행될 때, 공유 자원에 접근하는 코드의 일부를 의미합니다. 임계 영역 문제는 이러한 공유 자원에 대한 동시 접근을 제어하여 데이터의 일관성과 무결성을 유지해야 한다.

임계 영역에 여러 접근이 동시에 발생하는 것을 방지하려면 다음 3가지 조건이 충족되어야 한다.

  1. 상호 배제(Mutual Exclusion): 임계 영역에는 한 번에 하나의 프로세스(또는 스레드)만이 진입할 수 있어야 합니다.
  2. 진행(Progress): 임계 영역에 진입을 요청하는 프로세스가 없거나, 임계 영역 내에 있지 않은 프로세스만이 임계 영역 진입의 결정을 할 수 있어야 합니다.
  3. 유한 대기(Bounded Waiting): 어떤 프로세스도 무한히 대기하지 않아야 하며, 모든 프로세스가 결국에는 임계 영역에 진입할 수 있는 기회를 가져야 합니다.'

임계 영역 해결을 위한 동기화 메커니즘

  1. 뮤텍스(Mutexes): 상호 배제를 보장하기 위해 사용되며, 임계 영역에 진입하기 전에 락을 획득하고, 나갈 때 락을 해제합니다.

임계 영역에 접근하지 못한 프로세스는 락을 얻기 위해 기다리는 동안 락이 풀렸는지 반복문을 돌면서 확인한다.
이를 빠쁜 대기(busy waiting)의 한 종류인 스핀락이라고 한다.

즉, 스핀락(spinlock)은 락을 얻기 위해 프로세스가 반복문을 돌면서 기다리는 것을 의미한다. 프로세스가 대기 상태가 되지 않고 반복문을 돌면서 자원의 사용 가능 여부를 확인하므로 프로세스가 빠르게 교체될 수 있다.

  1. 세마포어(Semaphores): 뮤텍스와 유사하지만, 세마포어는 동시에 여러 프로세스가 공유 자원에 접근할 수 있도록 허용할 수 있는 카운트를 기반으로 한 메커니즘입니다.

임계 영역에 접근할 수 있는 키 n개를 지정하고 이 중 하나를 가진 프로세스만이 임계 영역에 접근하게 하는 방식이다. 이 방식은 공유 자원에 접근한 프로세스가 접근을 해제하면 다른 프로세스가 접근할 수 있도록 신호를 보낸다고 해서 시그널링 메커니즘 이라고도 한다.

교착상태

교착상태(Deadlock)는 멀티테스킹 환경에서 발생할 수 있는 문제로, 두 개 이상의 프로세스나 스레드가 서로의 작업이 끝나기를 무한정 기다리고 있어서, 그 어느 것도 진행될 수 없는 상태를 말합니다. 즉, 각각의 프로세스가 서로가 가진 자원을 요구하지만, 아무도 자원을 양보하지 않아 발생하는 상태입니다. 이는 시스템의 성능 저하나 시스템 정지 같은 심각한 문제를 초래할 수 있습니다.

교착상태의 조건

교착상태가 발생하기 위해서는 다음 네 가지 조건이 모두 충족되어야 합니다

  1. 상호 배제(Mutual Exclusion): 한 번에 하나의 프로세스만이 자원을 사용할 수 있습니다.
  2. 점유 대기(Hold and Wait): 최소한 하나의 자원을 점유하면서, 추가적인 자원을 기다리는 프로세스가 존재해야 합니다.
  3. 비선점(No Preemption): 다른 프로세스가 이미 점유하고 있는 자원을 강제로 빼앗을 수 없습니다.
  4. 환형 대기(Circular Wait): 대기하는 프로세스들 사이에 환형 구조를 이루어야 하며, 각 프로세스는 순환적으로 다음 프로세스가 요구하는 자원을 가지고 있어야 합니다.

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

  1. 상호배제 부정 : 여러 프로세스가 동시에 하나의 공유자원을 사용할 수 있게 한다.
  2. 점유와 대기 부정 : 프로세스가 실행되기 전에 필요한 모든 자원을 할당함으로써 프로세스 대기를 없앤다. 또는 프로세스가 자원을 점유하지 않은 상태에서만 자원을 요구하게 된다.
  3. 비선점 부정 : 자원을 점유한 프로세스가 다른 자원을 요구할 때 점유한 자원을 반납하게 한다.
  4. 환형 대기 부정 : 자우너을 선형 순서로 정렬해 고유 번호를 할당한다. 그리고 각 프로세스에서 요구할 수 있는 번호의 방향을 정해서 한쪽 방향으로만 자원을 요구하게 한다.

스레드 안전

스레드 안전(thread safety)이란, 여러 스레드가 동시에 같은 데이터에 접근하더라도 프로그램의 실행 결과가 변경되지 않도록 보장하는 것을 말합니다. 멀티스레딩 환경에서는 여러 스레드가 동시에 데이터를 읽고 쓰려고 할 때, 예상치 못한 결과나 데이터 손상이 발생할 수 있습니다.

스레드 안전성을 확보하는 방법은 여러 가지가 있으나, 주로 다음과 같은 기법들이 사용됩니다:

1. 뮤텍스(Mutex) 및 세마포어(Semaphore): 공유 자원에 대한 접근을 제어하기 위해 뮤텍스나 세마포어 같은 동기화 메커니즘을 사용합니다. 이러한 메커니즘은 한 번에 하나의 스레드만 공유 자원에 접근할 수 있도록 합니다.

2. 원자적 연산(Atomic Operations): 원자적 연산을 사용하면 복잡한 연산이더라도 중간에 다른 스레드에 의해 방해받지 않고 '분할 불가능한' 하나의 단위로 실행됩니다.

3. 불변 객체(Immutable Objects): 데이터가 생성된 후에는 변경되지 않는 객체를 사용함으로써 스레드 안전성을 확보할 수 있습니다. 객체가 불변이면 여러 스레드가 동시에 객체를 참조해도 문제가 발생하지 않습니다.

4. 스레드 로컬 저장소(Thread Local Storage): 각 스레드가 데이터의 자체 복사본을 가지고 있어서 다른 스레드와 데이터를 공유하지 않는 방식입니다. 이 방법을 사용하면 스레드 간의 데이터 충돌을 방지할 수 있습니다.

IPC

IPC(Inter-Process Communication)는 서로 다른 프로세스 간에 데이터를 교환하는 메커니즘입니다. 이는 운영 체제가 제공하는 기능으로, 프로세스들이 서로 정보를 공유하고, 동기화하며, 협업을 할 수 있게 해줍니다.

IPC 메커니즘에는 여러가지가 있습니다.

1. 공유 메모리(Shared Memory): 두 프로세스가 시스템의 동일한 메모리 영역을 공유하여 데이터를 교환할 수 있게 합니다. 가장 빠른 데이터 교환 방식 중 하나입니다.

2. 소켓(Sockets): 네트워크를 통한 통신을 가능하게 하는 인터페이스로, 일반적으로 서로 다른 호스트에서 실행되는 프로세스 간 통신에 사용됩니다.

3. 파이프(Pipes): 일반적으로 한 프로세스의 출력을 다른 프로세스의 입력으로 연결하는데 사용됩니다. 단방향 통신 채널입니다. 따라서 양방향 통신을 하려면 읽기 파이프와 쓰기 파이프를 각각 생성해야 합니다.

4. 메시지 큐(Message Queues): 프로세스들이 메시지의 형태로 데이터를 교환할 수 있게 해주며, 비동기적 통신을 지원합니다.

좀비 프로세스, 고아 프로세스

좀비 프로세스는 종료되었지만, 부모 프로세스가 종료 상태를 회수하지 않아 프로세스 테이블에서 완전히 제거되지 않은 상태의 프로세스를 말합니다. 이런 프로세스는 시스템의 리소스를 거의 사용하지 않지만, 프로세스 테이블에서 공간을 차지하여 시스템의 성능에 영향을 줄 수 있습니다. 부모 프로세스가 wait() 시스템 콜을 사용하여 자식 프로세스의 종료 상태를 회수하면 좀비 프로세스는 시스템에서 완전히 제거됩니다.

고아 프로세스는 부모 프로세스가 종료되었지만, 자신은 아직 종료되지 않은 프로세스를 말합니다. 부모 프로세스가 종료될 때, 시스템은 고아가 된 모든 자식 프로세스를 init 프로세스(프로세스 ID가 1인 프로세스)의 자식으로 채택하여, 이후에 init 프로세스가 자식 프로세스의 종료 상태를 회수합니다. 이 과정을 통해 고아 프로세스는 시스템의 리소스를 정상적으로 해제하고 종료될 수 있습니다.

profile
Android Developer

0개의 댓글