1. 스레드

스레드는 프로세스의 실행 가능한 가장 작은 단위입니다. 하나의 프로세스는 여러 스레드를 가질 수 있습니다. 최소한 하나의 스레드를 갖고 있어야 합니다.

출처: https://velog.io/@aeong98/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9COS-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C

 

프로세스는 독립된 메모리 주소 공간을 가지며 이 공간에는 코드, 데이터, 스틱, 힙이 포함됩니다. 프로세스 내의 스레드는 스레드끼리 프로세스의 자원(코드, 데이터, 힙)을 공유합니다. 그 외의 영역은(스택 영역 등)은 스레드끼리 공유하지 않으며 독립적으로 갖고 있습니다.

 

2. 싱글스레딩 vs 멀티스레딩

싱글스레딩프로그램이 하나의 스레드로 실행되는 방식인 반면, 멀티스레딩프로그램이 여러 개의 스레드로 실행되는 방식입니다.

출처: https://velog.io/@gil0127/%EC%8B%B1%EA%B8%80%EC%8A%A4%EB%A0%88%EB%93%9CSingle-thread-vs-%EB%A9%80%ED%8B%B0%EC%8A%A4%EB%A0%88%EB%93%9C-Multi-thread-t5gv4udj

2-1. 싱글스레딩

  • 장점
    - 단순한 작업에 적합
    - 구현이 간단하며 스레드 간의 동기화나 데이터 공유에 대한 걱정 없음
  • 단점
    - 한 번에 하나의 작업만 수행할 수 있음
    - 하나의 작업이 완료된 후에야 다음 작업을 시작할 수 있음(순차적으로 작업 실행)
    - CPU 활용도가 낮고 복잡한 작업에는 비효율적일 수 있음

2-2. 멀티스레딩

  • 장점
    - 각 스레드는 독립적으로 실행되며 동시에 여러 작업을 수행할 수 있음
    - 스레드 간 자원 공유와 통신이 가능하여 효율적인 협업이 이루어짐
    - 병렬 처리를 통해 CPU 활용도를 높일 수 있음
    - 복잡한 작업이나 I/O작업이 많은 경우에 효과적(한 스레드가 중단(blocked)되어도 다른 스레드는 실행 상태(running)일 수 있기 때문에 중단되지 않은 빠른 처리 가능)
  • 단점
    - 스레드 2개 이상이 공유 데이터에 접근하면 문제가 발생할 수 있음 -> 스레드 동기화 필요(데이터의 일관성과 정확성을 유지하기 위해 스레드들의 실행 순서를 제어하는 방법)
    - 구현이 상대적으로 복잡하고 디버깅이 어려울 수 있음
    - 한 스레드에 문제가 생기면 다른 스레드에도 영향을 끼쳐 프로세스에 영향을 줄 수 있음
  싱글스레딩 멀티스레딩
스레드 수 1개 여러 개
자원 사용 낮음 높음
구현 난이도 낮음 높음
성능 일반적으로 낮음 높음(특히 멀티코어/멀티CPU에서)
동기화 문제 X O(교착 상태(Deadlock) 등)

3. 공유 자원

공유 자원(Shared Resource)은 시스템 안에서 각 프로세스, 스레드가 함께 접근할 수 있는 모니터, 프린터, 메모리, 파일, 데이터 등의 자원이나 변수 등을 말합니다. 

3-1. 경쟁 상태(Race Condition)

공유 자원을 두 개 이상의 프로세스가 동시에 읽거나 쓰는 상황을 경쟁 상태(race condition)라고 합니다.

예를 들어, 두 스레드가 같은 변수를 동시에 수정하려고 할 때 경쟁 상태가 발생하는 상황입니다.

3. 임계 영역(Critical Section)

임계 영역은 둘 이상의 스레드가 공유 자원에 접근할 때 동시에 실행되면 안되는 코드 영역을 말합니다. 임계 영역에서는 고유 자원이 변경될 수 있으므로 한 번에 하나의 스레드만 이 구간을 실행할 수 있어야 합니다. 임계 영역 문제를 해결하기 위해서는 다음과 같은 조건을 만족해야 합니다.

  1. 상호 배제(Mutual Exclusion): 한 시점에 하나의 스레드만 임계 영역을 실행할 수 있습니다.
  2. 진행(Progress): 임계 영역에 들어가려는 스레드가 선택되어야 하며, 이 선택은 무한히 지연될 수 없습니다.
  3. 한정된 대기(Bouned Waiting): 한 스레드가 임계 영역에 들어가기 위해 대기하는 시간은 한정되어 있어야 합니다. 다시 말해, 무한히 대기 상태에 머물 수 없습니다. 

임계 영역의 동시 접근을 해결하기 위한 방법은 크게 뮤텍스, 세마포어, 모니터가 있습니다.

 

뮤텍스(mutex, mutual exclusion의 약자)

뮤텍스는 임계 영역에 상호 배제를 보장하는 잠금 메커니즘입니다.

뮤텍스는 잠금(lock())과 해제(unlock()), 두 가지의 상태를 가집니다. 임계 영역을 실행하려는 스레드는 먼저 뮤텍스를 획득(잠금)해야 합니다. 임계 영역을 빠져나올 때는 뮤텍스를 반납(해제)합니다. 만약 스레드가 뮤텍스를 이미 획득한 상태라면 다른 스레드는 뮤텍스가 해제될 때까지 대기해야 합니다.

 

세마포어(semaphore)

세마포어는 일반화된 뮤텍스입니다. 정수 값을 가지는 변수로, 여러 개의 스레드가 공유 자원에 접근할 수 있는 개수를 제한합니다. 정수와 wait()(또는 P())와 signal()(또는 V()) 함수로 공유 자원에 대한 접근을 처리합니다. 

  • wait(): 자신의 차례가 올 때까지 기다리는 함수
  • signal(): 다음 프로세스로 순서를 넘겨주는 함수 

세마포어는 다음과 같이 작동합니다. 

  1. 세파모어는 초기값으로 설정됩니다. 이 값은 동시에 공유 자원이 접근할 수 있는 스레드의 수를 나타냅니다.
  2. wait()연산: 공유 자원에 접근하기 전에 스레드는 wait 연산을 호출합니다. 이 연산은 세마포어의 값을 감소시키고 값이 0보다 작아지면 해당 스레드는 대기 상태가 됩니다.
  3. signal()연산: 공유 자원을 사용한 후에 스레드는 signal 연산을 호출합니다. 이 연산은 세마포어의 값을 증가시키고, 대기 중인 스레드 중 하나를 깨워서 진행합니다.

세마포어에는 카운팅 세마포어바이너리 세마포어가 있습니다.

  1. 카운팅 세마포어(counting semaphore)
    값이 0 이상의 정수를 가질 수 있는 세마포어입니다. 여러 개의 스레드가 공유 자원에 접근할 수 있는 개수를 제한하는 데 사용됩니다.
  2. 바이너리 세마포어(binary semaphore)
    값이 0 또는 1만 가능한 세마포어입니다. 상호 배제를 구현하는데 사용되며 뮤텍스와 유사한 역할을 합니다. 뮤텍스는 잠금을 기반으로 상호배제가 일어나는 '잠금 메커니즘'이고, 세마포어는 신호를 기반으로 상호 배제가 일어나는 '신호 메커니즘'입니다.

모니터(monitor)

모니터는 둘 이상의 스레드나 프로세스가 공유 자원에 안전하게 접근할 수 있도록 공유 자원을 숨기고 해당 접근에 대해 인터페이스만 제공합니다. 모니터큐를 통해 공유 자원에 대한 작업들을 순차적으로 처리합니다.

 

4. 교착 상태

교착상태(deadlock)는 두 개 이상의 프로세스 또는 스레드가 서로가 가진 자원을 기다리면서 무한정 대기하는 상태을 말합니다.

출처: https://lealea.tistory.com/244

교착상태를 잘 설명하는 예시로 '식사하는 철학자들' 문제가 있습니다.

다섯 명의 철학자가 하나의 원탁에 앉아 식사를 한다. 각각의 철학자들 사이에는 포크가 하나씩 있고, 앞에는 접시가 있다. 접시 안에 든 요리는 포크를 두개 사용하여 먹어야만 하는 스파게티이다. 그리고 각각의 철학자는 다른 철학자에게 말을 할 수 없으며, 번갈아가며 각자 식사하거나 생각하는 것만 가능하다. 따라서 식사를 하기 위해서는 왼쪽과 오른쪽의 인접한 철학자가 모두 식사를 하지 않고 생각하고 있어야만 한다. 또한 식사를 마치고 나면, 왼손과 오른손에 든 포크를 다른 철학자가 쓸 수 있도록 내려놓아야 한다. 이 때, 어떤 철학자도 굶지 않고 식사할 수 있도록 하는 방법은 무엇인가?

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

  • 상호 배제(Mutual Exclstion): 한 번에 하나의 프로세스만 자원을 사용할 수 있어야 합니다.
  • 점유 대기(Hold and Wait): 프로세스가 적어도 하나의 자원을 점유하고 있으면서, 다른 프로세스가 점유하고 있는 자원을 기다려야 합니다.
  • 비선점(No Preemption): 프로세스가 점유하고 있는 자원을 강제로 빼앗을 수 없어야 합니다.
  • 순환 대기(Circular Wait): 각 프로세스가 순환적으로 다음 프로세스가 요구하는 자원을 점유하고 있어야 합니다.

교착 상태의 해결 방법은 크게 4가지로 나눌 수 있습니다.

1️⃣ 예방(Prevention): 교착 상태의 조건 중 하나를 만족하지 않도록 시스템을 설계합니다.

2️⃣ 회피(Avoidance): 자원 요청 시 교착 상태가 발생할 가능성이 있는지 미리 검사하고 안전한 경우에만 자원을 할당압니다. 대표적으로 "은행원 알고리즘"을 씁니다.

3️⃣ 탐지(Detection) 및 회복: 회복(Recovery): 교착 상태가 발생하면 교착 상태에 있는 프로세스를 하나씩 강제로 종료하거나 교착상태가 회복될 때까지 한 프로세스에게 자원을 몰아줍니다.

4️⃣ 무시(Ignorance): 교착 상태는 매우 드물게 일어나기 때문에 이를 처리하는 비용이 더 큽니다. 따라서 교착 상태가 발생하면 사용자가 작업을 종료하게 합니다. 많은 운영체제가 이 방법을 사용하고 있습니다.

728x90

'운영체제' 카테고리의 다른 글

[운영체제] CPU 스케줄링 알고리즘  (0) 2024.05.10
[운영체제] 멀티 프로세싱  (0) 2024.05.09
[운영체제] 프로세스  (0) 2024.05.08
[운영체제] 메모리 관리  (0) 2024.05.05
[운영체제] 캐시(Cache)  (0) 2024.05.04

+ Recent posts