포스트

[Interview] OS

프로세스와 스레드의 차이점


  • 프로세스와 스레드 개념은 다음과 같다.

    용어설명
    프로세스CPU에 의해 처리되는 사용자 프로그램, 시스템 프로그램, 즉 실행 중인 프로그램
    스레드프로세스보다 가벼운, 독립적으로 수행되는 순차적인 제어의 흐름이며, 실행 단위임
  • 한 개의 프로세스는 여러 개의 스레드를 가질 수 있다.

    이미지

    • pthread_create는 새로운 쓰레드를 생성한다.
    • fork는프로세스를 copy하여 자식 프로세스를 생성하는 시스템콜이다.
      • 같은 프로그램에서 새로운 제어 흐름을 만드는 용도. 대개 새로운 제어 흐름은 스레드를 통해 만든다. 스레드를 만드는 것보다 프로세스를 만드는 것이 안정성 측면에서 더 나을 수 있기 때문에 절대적으로 우월한 것은 아니다.
      • 다른 프로그램을 실행하는 새 프로세스를 만드는 용도. 예를 들면 쉘에서 명령어를 통해 프로세스를 실행하면 쉘은 fork()를 통해 자식 프로세스를 만들고, exec()를 통해 주어진 명령에 해당하는 프로그램을 실행한다.
      • 자식 프로세스가 생성되면서 부모 프로세스의 Stack, Heap, Data 뿐만 아니라 부모 프로세스의 PCB(Process Control Block)도 그대로 복사한다. 텍스트(text, 프로그램 코드)영역은 공유한다.

      이미지

  • 주소 공간
    • 프로세스: 각 프로세스는 독립적인 주소 공간을 가진다.
    • 스레드: 같은 프로세스 내의 스레드들은 주소 공간을 공유한다.
  • 자원 할당
    • 프로세스: 각 프로세스는 고유의 자원(CPU 시간, 메모리 등)을 할당받아 사용한다.
    • 스레드: 스레드는 프로세스의 자원을 공유하면서 사용한다.
  • 안정성
    • 프로세스: 프로세스 간의 메모리 침범이 불가능해 안정적이다.
    • 스레드: 스레드 간의 메모리 침범이 가능해 동기화 문제를 일으킬 수 있다.
  • 통신
    • 프로세스: 프로세스 간의 통신은 IPC(Inter-Process Communication) 기법을 사용하여 수행된다.
      • IPC (Inter Process Communication)는 프로세스 간 통신 기술이다.
        • IPC 기법에는 메시지 큐, 공유메모리, 소켓, 세마포어가 있다.

          기법설명
          메시지 큐메시지(또는 패킷) 단위로 동작하여 프로세스 간 통신함
          공유 메모리한 프로세스의 일부분을 다른 프로세스와 공유
          소켓클라이언트와 서버 프로세스 둘 사이에 통신을 가능하게 함
          세마포어프로세스 사이의 동기를 맞추는 기능을 제공함
    • 스레드: 스레드 간의 통신은 공유 메모리를 통해 효율적으로 수행된다.
  • 생성과 종료
    • 프로세스: 프로세스 생성과 종료는 스레드에 비해 오버헤드가 크다.
    • 스레드: 스레드는 상대적으로 적은 오버헤드로 생성하고 종료할 수 있다.

요약


  • 프로세스: 고유의 주소 공간과 자원을 독립적으로 할당받아 사용. 서로 다른 프로세스 간의 자원 공유가 어려움.
  • 스레드: 동일한 프로세스 내에서 주소 공간과 자원을 공유하여 사용. 자원 공유와 통신이 효율적이지만, 동기화 문제가 발생할 수 있음.
  • 프로세스와 스레드는 각각의 특징과 장단점이 있어, 상황에 맞게 적절하게 사용되어야 한다. 프로세스는 독립적인 실행 환경이 필요한 경우, 스레드는 자원 공유와 통신이 빈번히 필요한 경우에 적합하다.

멀티 프로세스로 처리 가능한 작업을 굳이 멀티 스레드로 하는 이유는?


  1. 자원 효율적 관리:
    • 프로세스를 생성하고 자원을 할당하는 시스템 콜은 비용이 많이 든다. 스레드는 동일한 프로세스 내에서 실행되므로, 프로세스 생성에 비해 자원 할당 시스템 콜이 적어 자원을 효율적으로 관리할 수 있다.
  2. 통신 비용 감소:
    • 프로세스 간의 통신(IPC)은 비용이 많이 드는 작업이다. 반면, 스레드는 동일한 주소 공간을 공유하므로, 스레드 간의 통신 비용이 훨씬 적다. 이는 작업 간의 부담을 줄여 성능을 향상시킨다.
  3. 문제 해결을 위한 동기화:
    • 멀티 스레드를 사용할 때는 공유 자원으로 인한 문제를 해결하기 위해 동기화에 신경 써야 한다. 하지만 동기화 기법을 잘 활용하면, 멀티 스레드는 높은 성능과 효율성을 제공한다.

요약


  • 자원 효율적 관리: 스레드는 프로세스 생성에 비해 시스템 콜 비용이 적어 자원을 효율적으로 관리.
  • 통신 비용 감소: 스레드 간 통신 비용이 적어 작업 간 부담이 감소.
  • 동기화 관리 필요: 공유 자원 문제 해결을 위해 동기화에 신경 써야 하지만, 효율적인 성능 제공.

교착상태(DeadLock)란 무엇이며, 4가지 조건은?


  • 교착상태(DeadLock)는 프로세스가 자원을 얻지 못해 다음 처리를 하지 못하는 상태를 말한다. 이는 시스템적으로 한정된 자원을 여러 프로세스가 사용하려 할 때 발생한다.
  • 교착상태가 발생하는 4가지 조건은 다음과 같다.
    1. 상호배제 (Mutual Exclusion):
      • 프로세스들이 필요로 하는 자원에 대해 배타적 통제권을 요구한다. 즉, 한 번에 하나의 프로세스만 자원을 사용할 수 있다.
    2. 점유대기 (Hold and Wait):
      • 프로세스가 할당된 자원을 가진 상태에서 다른 자원을 기다린다. 즉, 한 프로세스가 자원을 점유한 채 다른 자원을 기다리는 상황이다.
    3. 비선점 (No Preemption):
      • 프로세스가 어떤 자원을 사용하는 동안 그 자원을 강제로 빼앗을 수 없다. 자원을 사용 중인 프로세스가 사용을 끝낼 때까지 기다려야 한다.
    4. 순환대기 (Circular Wait):
      • 각 프로세스는 순환적으로 다음 프로세스가 요구하는 자원을 가지고 있다. 예를 들어, 프로세스 A는 프로세스 B가 점유한 자원을 기다리고, 프로세스 B는 프로세스 C가 점유한 자원을 기다리고, 프로세스 C는 프로세스 A가 점유한 자원을 기다리는 상황이다. - 이 4가지 조건 중 하나라도 만족하지 않으면 교착상태는 발생하지 않는다. 특히, 순환대기는 점유대기와 비선점 조건을 모두 만족해야 성립한다.

요약


  • 교착상태(DeadLock): 프로세스가 자원을 얻지 못해 다음 처리를 못하는 상태.
  • 상호배제 (Mutual Exclusion): 프로세스들이 배타적 자원 통제권 요구.
  • 점유대기 (Hold and Wait): 자원을 점유한 상태에서 다른 자원을 기다림.
  • 비선점 (No Preemption): 자원을 강제로 뺏을 수 없음.
  • 순환대기 (Circular Wait): 각 프로세스가 순환적으로 다음 프로세스가 요구하는 자원을 보유.
  • 교착상태는 위 조건 중 하나라도 만족하지 않으면 발생하지 않음.

교착상태 해결 방법 4가지


  1. 예방 (Prevention):
    • 교착상태 발생 조건 중 하나 이상을 제거하여 교착상태가 발생하지 않도록 한다.
      • 상호배제 조건 제거: 가능한 자원에 대해 상호배제 조건을 없앤다. 그러나 대부분의 자원은 상호배제를 요구하므로 이 방법은 현실적이지 않을 수 있다.
      • 점유대기 조건 제거: 모든 자원을 한꺼번에 할당하거나, 자원이 필요 없을 때 자원을 해제한다.
      • 비선점 조건 제거: 자원이 다른 프로세스에 의해 점유되면, 점유 중인 자원을 강제로 빼앗을 수 있도록 한다.
      • 순환대기 조건 제거: 자원에 순서를 부여하여, 각 프로세스가 자원을 요청할 때 정해진 순서대로만 요청하도록 한다.
  2. 회피 (Avoidance):
    • 시스템이 항상 안전 상태에 있도록 한다. 자원을 할당하기 전에, 자원을 할당했을 때 시스템이 안전 상태인지 확인한다.
      • 은행가 알고리즘 (Banker’s Algorithm): 프로세스들이 자원을 요청할 때마다 시스템이 안정 상태에 있는지 확인하고, 안정 상태라면 자원을 할당하고, 그렇지 않다면 자원 할당을 거부한다.
  3. 무시 (Ignore):
    • 교착상태가 드물게 발생한다고 가정하고, 교착상태에 대한 특별한 대처를 하지 않는다.
      • 일반적으로 사용되는 방식: 특히, 교착상태가 발생하더라도 큰 문제가 되지 않는 시스템에서 사용된다. 예를 들어, 데스크탑 운영체제에서는 교착상태가 드물게 발생하므로 대부분의 경우 무시한다.
  4. 발견 (Detection):
    • 교착상태가 발생했는지 주기적으로 검사하고, 교착상태가 발견되면 이를 해결하기 위한 조치를 취한다.
      • 자원 할당 그래프 (Resource Allocation Graph): 자원 할당 그래프를 통해 교착상태를 검사한다.
      • 교착상태 해결 방법: 교착상태가 발생했을 경우, 한 프로세스를 강제로 종료하거나, 자원을 회수하여 교착상태를 해소한다.

요약


  1. 예방 (Prevention):
    • 교착상태 발생 조건 중 하나 이상을 제거.
      • 상호배제 조건 제거: 상호배제 조건을 없애기.
      • 점유대기 조건 제거: 모든 자원을 한꺼번에 할당 또는 필요 없을 때 자원 해제.
      • 비선점 조건 제거: 자원을 강제로 빼앗을 수 있도록 함.
      • 순환대기 조건 제거: 자원에 순서를 부여하고 정해진 순서대로 요청.
  2. 회피 (Avoidance):
    • 시스템이 항상 안전 상태에 있도록 자원을 할당.
      • 은행가 알고리즘: 안정 상태를 확인하고 자원을 할당.
  3. 무시 (Ignore):
    • 교착상태가 드물게 발생한다고 가정하고 특별한 대처를 하지 않음.
      • 일반적으로 사용되는 방식: 특히, 교착상태가 드물게 발생하는 시스템에서 사용.
  4. 발견 (Detection):
    • 교착상태가 발생했는지 주기적으로 검사하고, 교착상태가 발견되면 이를 해결하기 위한 조치.
      • 자원 할당 그래프: 교착상태를 검사.
      • 교착상태 해결 방법: 한 프로세스를 강제로 종료하거나 자원을 회수하여 해결.

메모리의 특징


  • 지역성(Locality)
    • 기억장치는 지역성이라는 특성을 가지고 있으며, 이는 메모리 접근 패턴이 시간적 및 공간적으로 일관성을 보인다는 것을 의미한다.
      • 시간적 지역성(Temporal Locality): 한 번 참조된 데이터는 곧바로 다시 참조될 가능성이 높은 특성이다. 예를 들어, 반복문 내의 변수 접근처럼 짧은 시간 내에 동일한 메모리 위치를 여러 번 읽거나 쓰는 경우이다.
      • 공간적 지역성(Spatial Locality): 어떤 데이터가 참조되면 그 데이터와 가까운 위치에 있는 다른 데이터가 곧바로 참조될 가능성이 높은 특성이다. 예를 들어, 배열의 요소에 순차적으로 접근하는 경우이다.

메모리 계층 구조


  • 기억장치는 지역성의 원리를 이용하여 계층적으로 구성되며, 상위 계층일수록 접근 속도가 빠르고 비용이 높으며 용량은 적다.
  • 메모리 계층 구조는 CPU가 메모리에 더 빨리 접근할 수 있도록 메모리를 여러 종류로 나누어 둔 것을 의미한다. 각 계층의 특징은 다음과 같다.

    이미지

    • 레지스터 (Register)
      • 설명: CPU 내부에 있는 소형의 고속 메모리
      • 특징: 매우 빠른 접근 속도를 가지며, 주로 연산 중인 데이터나 명령어를 저장
      • 용도: 계산, 명령어 실행, 데이터 처리 등의 임시 저장소로 사용
    • 캐시 (Cache)
      • 설명: CPU와 메인 메모리 사이에 위치한 고속 메모리
      • 특징: 접근 속도가 빠르며, 자주 사용되는 데이터를 저장하여 CPU의 데이터 접근 시간을 줄임
      • 용도: CPU 연산의 효율을 높이기 위해 자주 사용하는 데이터나 명령어를 캐싱
    • 메모리 (Memory)
      • 설명: 주 메모리 또는 RAM으로 불리는 공간
      • 특징: 상대적으로 큰 용량을 가지며, 실행 중인 프로그램과 데이터를 저장
      • 용도: 프로그램 실행 시 필요한 데이터와 명령어를 저장하고 접근하는 데 사용
    • 하드디스크 (Hard Disk)
      • 설명: 영구 저장 장치로, 데이터를 지속적으로 보관
      • 특징: 접근 속도가 느리지만, 대용량 데이터를 저장 가능
      • 용도: 운영체제, 응용 프로그램, 사용자 데이터 등을 저장하는 데 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[레지스터(Register, CPU), 캐시 기억장치(Cache Memory, CPU), 주기억장치(Main Memory, 메모리), 보조기억장치(Secondary Storage, 하드디스크)]
1.레지스터(Register)
위치: CPU 내부
특징: 가장 빠른 메모리로, CPU의 일부이다. 일반적으로 CPU 명령어 실행 중에 필요한 데이터를 저장한다.

2. 캐시 기억장치(Cache Memory)
위치: CPU 내부(L1, L2 캐시)와 CPU 외부에 가까운 위치(L3 캐시)
특징: 매우 빠른 속도의 메모리로, 자주 사용되는 데이터나 명령어를 저장하여 CPU의 접근 시간을 줄인다.

3. 주기억장치(Main Memory)
위치: CPU 외부
특징: RAM(Random Access Memory)으로, 현재 실행 중인 프로그램과 데이터를 저장한다. 캐시보다는 느리지만 보조기억장치보다는 빠르다.

4. 보조기억장치(Secondary Storage)
위치: 시스템 외부
특징: 하드디스크(HDD), SSD(Solid State Drive)와 같은 장치로, 데이터를 영구적으로 저장한다. 주기억장치보다 훨씬 큰 용량을 제공하지만 접근 속도는 느리다.

메모리 계층 구조의 작동 원리


일반적으로 레지스터와 캐시는 CPU 내부에 존재한다. 이는 CPU가 아주 빠르게 접근할 수 있다는 것을 의미한다. 메모리는 CPU 외부에 존재하므로, 레지스터와 캐시보다 접근 속도가 느리다. 하드 디스크는 CPU가 직접 접근할 방법이 없으며, CPU가 하드 디스크에 접근하기 위해서는 하드 디스크의 데이터를 메모리로 이동시키고, 메모리를 통해 접근해야 한다. 이 과정은 매우 느린 접근만 가능하게 한다.

이미지

메모리 성능 요인


  • 메모리의 성능은 다음과 같은 요인들에 의해 결정된다.
    • 기억 용량(Capacity): 저장할 수 있는 데이터의 총량. 용량이 클수록 많은 데이터를 저장할 수 있다.
    • 접근 시간(Access Time): 데이터를 읽거나 쓰는 데 걸리는 시간. 접근 시간이 짧을수록 메모리의 성능이 높아진다.
    • 사이클 시간(Cycle Time): 메모리의 연속된 두 접근 간에 필요한 최소 시간. 사이클 시간이 짧을수록 빠르게 연속된 데이터를 접근할 수 있다.
    • 기억 장치 대역폭(Bandwidth): 일정 시간 동안 메모리에서 읽거나 쓸 수 있는 데이터의 양. 대역폭이 높을수록 메모리 성능이 향상된다.
    • 가격(Cost): 메모리 용량당 비용. 일반적으로 용량이 크고 속도가 빠를수록 비용이 높다.
  • 이러한 요인들은 메모리의 계층 구조와 지역성의 특성에 따라 다양한 방식으로 최적화되어 시스템의 전반적인 성능을 향상시킨다.

메모리 할당 알고리즘


First Fit

  • 설명: 메모리의 처음부터 검사하여 크기가 충분한 첫 번째 메모리 공간에 할당
  • 특징: 검색 시간이 짧아 빠르지만, 메모리의 단편화가 발생할 수 있음

Next Fit

  • 설명: 마지막으로 참조한 메모리 공간에서부터 탐색을 시작해 크기가 충분한 공간에 할당
  • 특징: First Fit과 유사하지만, 이전 검색 위치에서부터 시작하므로 메모리의 앞부분이 집중적으로 사용되는 것을 방지

Best Fit

  • 설명: 모든 메모리 공간을 검사하여 내부 단편화가 가장 적은 공간에 할당
  • 특징: 메모리 단편화를 최소화하지만, 검색 시간이 길어질 수 있음

페이지 교체 알고리즘


  • OPT (Optimal Page Replacement)
    • 설명: 앞으로 가장 오랫동안 사용하지 않을 페이지를 교체
    • 특징: 이론적으로 최적의 성능을 보장하지만, 실제 구현이 어려움
  • FIFO (First-In, First-Out)
    • 설명: 메모리에 먼저 들어온 페이지를 먼저 교체
    • 특징: 구현이 간단하지만, Belady의 역설에 의해 성능이 비효율적일 수 있음
  • LRU (Least Recently Used)
    • 설명: 가장 오랫동안 사용되지 않은 페이지를 교체
    • 특징: 최근에 자주 사용된 페이지를 유지하여 실제 사용 패턴에 비교적 적합
  • LFU (Least Frequently Used)
    • 설명: 사용 빈도가 가장 적은 페이지를 교체
    • 특징: 사용 빈도를 기준으로 하여 자주 사용되는 페이지를 유지하지만, 최근 사용 여부를 고려하지 않음
  • NUR (Not Recently Used)
    • 설명: 최근에 사용되지 않은 페이지를 교체
    • 특징: 간단한 구현으로 최근 사용되지 않은 페이지를 교체하여 성능 향상 가능

외부 단편화와 내부 단편화


외부 단편화

  • 외부 단편화는 메모리에 사용 가능한 공간이 충분히 있지만, 그 공간이 연속적이지 않아 하나의 큰 작업을 수용할 수 없는 상태를 말한다.
  • 이는 메모리 블록이 여러 개로 나뉘어 있고, 각 블록이 작아서 필요한 크기의 메모리를 할당할 수 없는 경우에 발생한다.
  • 작업보다 많은 공간이 있더라도 실제로 그 작업을 받아들일 수 없는 경우 (메모리 배치에 따라 발생하는 문제)

내부 단편화

  • 내부 단편화는 할당된 메모리 블록이 실제로 필요한 크기보다 커서 발생하는 사용되지 않는 공간이다. 이는 메모리 할당 단위가 고정된 크기일 때, 실제 필요로 하는 공간보다 더 큰 블록이 할당되어 내부에 사용되지 않는 공간이 생기는 경우이다.
  • 작업에 필요한 공간보다 많은 공간을 할당받음으로써 발생하는 내부의 사용 불가능한 공간

가상 메모리란?


  • 가상 메모리는 실행 중인 프로세스가 실제 물리 메모리보다 더 큰 주소 공간을 사용할 수 있게 하는 메모리 관리 기법이다.
  • 가상 메모리는 프로세스가 마치 커다란 연속된 물리 메모리를 사용하는 것처럼 보이게 하여 메모리의 효율적인 사용과 프로그램 실행을 가능하게 한다.
  • 이는 페이지 파일 또는 스왑 공간을 활용하여 물리 메모리의 용량을 초과하는 데이터를 디스크에 저장하고 필요할 때 로드하는 방식으로 작동한다.
    1. 주소 공간 분리: 프로세스가 사용하는 주소(가상 주소)와 실제 물리적 메모리 주소를 분리하여, 프로세스가 물리적 메모리 크기 제한 없이 작동할 수 있게 한다.
    2. 페이지화: 물리적 메모리가 부족할 때, 사용하지 않는 데이터를 가상 메모리(일반적으로 디스크)에 저장하고, 실제 메모리에는 필요한 데이터만 유지한다.
    3. 동적 할당: 프로세스가 필요로 하는 메모리를 동적으로 할당하고, 필요에 따라 페이지를 교체하여 실제 메모리 공간을 효율적으로 사용한다.

주요 특징


  • 메모리 확장: 실제 메모리보다 큰 주소 공간을 사용할 수 있어, 큰 프로그램도 실행 가능하다.
  • 효율성: 실제 메모리와 가상 메모리를 조합하여, 자원을 효율적으로 관리한다.
  • 페이지 교체: 메모리 공간이 부족하면, 사용하지 않는 페이지를 디스크로 이동시키고, 필요한 페이지를 메모리에 로드하여 작업을 지속한다.

요약


  • 가상 메모리는 실제 메모리의 부족함을 보완하기 위해 사용되지만, 실제 메모리처럼 동작하지 않는다.
  • 실제 메모리가 부족할 때, 가상 메모리를 통해 데이터를 디스크에 저장하고, 필요한 데이터를 메모리에 로드하여 계속 작업을 진행한다.
  • 이는 실제 메모리에 사용되지 않는 공간이 없도록 하여, 메모리를 효율적으로 사용하는 것을 목표로 한다.

페이징과 세그먼테이션


페이징

  • 페이징은 메모리를 동일한 크기의 블록(페이지)으로 나누어 논리 주소와 물리 주소를 관리하는 기법이다.
  • 각 페이지는 메모리의 임의의 위치에 저장될 수 있으며, 논리 주소와 물리 주소의 변환은 메모리 관리 장치(MMU)에 의해 처리된다.
  • 페이징의 주요 특징은 외부 단편화를 제거할 수 있지만, 페이지 크기에 따른 내부 단편화가 발생할 수 있다는 점이다.

세그먼테이션

  • 세그먼테이션은 프로그램을 논리적 단위(세그먼트)로 나누어 메모리를 관리하는 기법이다.
  • 세그먼트는 서로 다른 크기를 가질 수 있으며, 프로그램 실행 시 필요한 만큼 메모리에 할당된다.
  • 세그먼테이션의 주요 특징은 프로그래머가 코드, 데이터, 스택 등을 별도로 관리할 수 있어 메모리 활용이 유연하다는 점이다. 하지만 외부 단편화가 발생할 수 있다.
1
2
3
4
5
6
7
8
[페이징]
- 페이지 단위의 논리-물리 주소 관리 기법
- 논리 주소 공간이 하나의 연속적인 물리 메모리 공간에 들어가야하는 제약을 해결하기 위한 기법 
- 논리 주소 공간과 물리 주소 공간을 분리해야함(주소의 동적 재배치 허용), 변환을 위한 MMU 필요
    
[세그먼테이션]
 - 사용자/프로그래머 관점의 메모리 관리 기법 
 - 페이징 기법은 같은 크기의 페이지를 갖는 것과는 다르게 논리적 단위(세그먼트)로 나누므로 미리 분할하는 것이 아니고 메모리 사용할 시점에 할당됨

뮤텍스와 세마포어


세마포어

  • 세마포어는 운영체제에서 공유 자원에 대한 접근을 제어하기 위해 사용되는 신호이다.
  • 세마포어는 특정 자원에 접근할 수 있는 최대 허용치를 지정하여 동시 접근을 제어한다. 세마포어는 여러 스레드가 동시에 자원에 접근하는 것을 허용하지만, 설정된 한계치를 넘지 못하도록 한다.
  • 카운트가 0이 되면 자원이 모두 사용 중임을 의미하며, 새로운 접근 요청은 대기 상태가 된다.

뮤텍스

  • 뮤텍스는 상호 배제 기법으로, 한 번에 하나의 스레드만 특정 자원에 접근할 수 있도록 제어한다.
  • 뮤텍스는 소유 개념을 가지고 있으며, 한 스레드가 뮤텍스를 소유하고 있는 동안 다른 스레드는 해당 자원에 접근할 수 없다. 이는 대기열(큐) 구조로 생각할 수 있다.

차이점

  • 세마포어는 여러 스레드가 동시에 자원에 접근할 수 있지만, 뮤텍스는 한 번에 하나의 스레드만 자원에 접근할 수 있다.(세마포어는 뮤텍스가 될 수 있지만, 뮤텍스는 세마포어가 될 수 없다.)
  • 세마포어는 소유 개념이 없지만, 뮤텍스는 소유 개념이 있다.
  • 세마포어는 동기화 개수 제한을 설정할 수 있지만, 뮤텍스는 그렇지 않다.

Context Switching이란?


  • Context Switching은 CPU가 한 프로세스에서 다른 프로세스로 전환되는 과정을 말한다. 이 과정에서 현재 실행 중인 프로세스의 상태를 저장하고, 다음에 실행할 프로세스의 상태를 로드한다.
  • 프로세스의 문맥은 PCB(Process Control Block)에 기록되며, CPU는 이 PCB를 참조하여 각 프로세스의 상태를 관리한다. Context Switching은 시스템 자원을 효율적으로 사용하고, 여러 프로세스가 CPU를 공유할 수 있도록 한다.

사용자 수준 스레드 vs 커널 수준 스레드 차이


사용자 수준 스레드

  • 장점:
    • 낮은 오버헤드: 사용자 수준 스레드는 커널 스케줄러를 호출할 필요가 없으므로 컨텍스트 스위칭 오버헤드가 적다. 이는 스레드 전환이 사용자 공간에서만 이루어지기 때문이다.
    • 빠른 전환: 커널 모드로 전환되지 않으므로 스레드 간 전환이 빠르다.
  • 단점:
    • 블로킹 문제: 한 스레드가 커널 모드로 진입하여 블로킹 상태가 되면, 동일 프로세스 내의 다른 스레드도 모두 정지된다. 이는 커널이 스레드의 존재를 알지 못하고, 프로세스를 하나의 단위로만 관리하기 때문이다.
    • 멀티프로세서 활용 제한: 사용자 수준 스레드는 커널 모드의 스케줄링 대상이 되지 않으므로, 멀티프로세서를 효율적으로 활용할 수 없다.

커널 수준 스레드

  • 장점:
    • 멀티프로세서 지원: 커널 수준 스레드는 멀티프로세서 시스템에서 효율적으로 동작할 수 있다. 커널 스케줄러가 각 CPU에 스레드를 적절히 분배하여 병렬 처리를 가능하게 한다.
    • 개별 스레드 관리: 커널이 각 스레드를 개별적으로 관리하여, 한 스레드의 블로킹이 다른 스레드에 영향을 주지 않는다.
  • 단점:
    • 높은 오버헤드: 컨텍스트 스위칭 시 사용자 모드와 커널 모드 간의 전환이 필요하므로, 오버헤드가 발생한다. 이는 빈번한 스위칭이 성능 저하를 초래할 수 있다.
    • 복잡한 구현: 커널 수준에서의 스레드 관리는 사용자 수준 스레드보다 더 복잡하며, 많은 리소스를 필요로 한다.

fork()vfork()의 차이점


fork()

  • 메모리 복사: fork() 시스템 호출은 부모 프로세스의 주소 공간을 복사하여 자식 프로세스를 생성한다. 자식 프로세스는 부모 프로세스와 독립적인 메모리 공간을 가지며, 이를 통해 독립적으로 실행된다.
  • 독립적인 실행: 자식 프로세스는 부모 프로세스와 독립적으로 실행되며, 메모리와 자원에 대한 충돌이 발생하지 않는다.
  • 오버헤드: 부모 프로세스의 주소 공간을 복사하는 과정에서 오버헤드가 발생한다. 이는 자식 프로세스 생성 속도를 느리게 할 수 있다.
  • 안정성: 메모리와 자원을 복사하여 사용하므로, 부모 프로세스와 자식 프로세스 간의 자원 충돌이 발생하지 않아 안정적이다.

vfork()

  • 메모리 공유: vfork() 시스템 호출은 부모 프로세스와 자식 프로세스가 주소 공간을 공유하여 자식 프로세스를 생성한다. 이로 인해 메모리 복사가 필요 없어 자식 프로세스 생성 속도가 매우 빠르다.
  • 자원 공유: 자식 프로세스가 부모 프로세스의 메모리와 자원을 공유하기 때문에, 자원에 대한 충돌이 발생할 수 있다. 이를 피하기 위해 부모 프로세스는 자식 프로세스가 exit()하거나 exec() 시스템 호출을 실행할 때까지 블록된다.
  • 빠른 생성: 메모리 복사가 없기 때문에 자식 프로세스 생성 속도가 빠르다.
  • 주의 필요: 메모리를 공유하기 때문에, 자식 프로세스가 부모 프로세스의 메모리를 변경하면 문제가 발생할 수 있다. 따라서 자식 프로세스는 빠르게 exec() 시스템 호출을 실행해야 한다.

Race Condition이란?


  • 정의
    • Race Condition은 두 개 이상의 프로세스가 공통 자원을 병행적으로 읽거나 쓰는 상황에서 발생한다. 이 경우, 공용 데이터에 대한 접근 순서에 따라 실행 결과가 달라지게 된다.
  • 발생 원인
    • 병행성: 다중 프로세스나 스레드가 동시에 실행되면서 공통 자원에 접근할 때 발생한다.
    • 비동기적 실행: 프로세스나 스레드가 비동기적으로 실행되기 때문에, 자원 접근 순서가 예측할 수 없게 된다.
  • 문제점
    • 일관성 문제: Race Condition이 발생하면 데이터의 일관성이 깨질 수 있다. 예를 들어, 두 프로세스가 동시에 데이터를 수정하면 예기치 않은 결과가 발생할 수 있다.
    • 결과 불확실성: 실행 결과가 접근 순서에 따라 달라지므로, 원하는 결과를 보장할 수 없다.
    • 디버깅 어려움: Race Condition은 간헐적으로 발생하므로, 디버깅과 문제 해결이 어렵다.
  • 해결 방법
    • 상호 배제: 상호 배제(Mutual Exclusion)를 통해 공통 자원에 대한 동시 접근을 방지할 수 있다. 이는 자원에 접근하는 코드 영역을 임계 구역(Critical Section)으로 설정하고, 하나의 프로세스나 스레드만 접근하도록 한다.
    • 락 사용: 뮤텍스(Mutex)나 세마포어(Semaphore) 같은 동기화 도구를 사용하여 자원에 대한 접근을 제어한다.
    • 모니터: 모니터(Monitor)를 사용하여 자원 접근을 자동으로 관리한다.
    • 데드락 방지: 적절한 락 순서와 타임아웃을 설정하여 데드락(Deadlock) 발생을 방지한다.
1
2
[레이스 컨디션 공격(Race Condition Attack)]
실행되는 프로세스가 임시파일을 만드는 경우 악의적인 프로그램을 통해 그 프로세스의 실행 중에 끼어들어 임시파일을 심볼릭 링크하여 악의적인 행위를 수행하게 하는 공격 기법

커널과 하드웨어


  • 리눅스에서 시스템 콜과 서브루틴의 차이점은 주로 기능과 수행 위치, 그리고 실행되는 환경의 차이에 있다. 이를 이해하기 위해 커널과 하드웨어 간의 관계를 먼저 살펴본다.
  • 커널은 하드웨어를 제어하고 관리하는 핵심 소프트웨어 계층이다. 커널은 하드웨어와 직접 상호작용하며, 사용자 프로그램이 하드웨어 자원을 안전하고 효율적으로 사용할 수 있도록 지원한다. 이는 일종의 API 역할을 하며, 하드웨어와 사용자 프로그램 간의 중개 역할을 한다.

서브루틴과 시스템 콜의 차이


서브루틴(Subroutine)

  • 정의: 서브루틴은 특정 작업을 수행하기 위해 작성된 코드 블록이다. 이는 프로그래머가 직접 작성하거나 표준 라이브러리에서 제공하는 함수들이다.
  • 예시: printf, scanf, strcmp, strcpy
  • 실행 환경: 사용자 모드에서 실행된다.
  • 기능: 서브루틴은 일반적으로 사용자 프로그램 내에서 로직을 구성하고 다양한 작업을 수행한다. 이는 커널이나 운영 체제의 개입 없이 직접 호출된다.
  • 호출 방식: 일반 함수 호출 방식으로 실행되며, CPU 모드 전환이 필요 없다.

시스템 콜(System Call)

  • 정의: 시스템 콜은 사용자 프로그램이 운영 체제 커널의 기능을 호출하는 방법이다. 이는 하드웨어 자원에 대한 접근이나 커널 수준의 작업을 수행하기 위해 사용된다.
  • 예시: open, read, write, fork, execve
  • 실행 환경: 커널 모드에서 실행된다.
  • 기능: 시스템 콜은 프로세스 관리, 파일 시스템 접근, 디바이스 제어 등과 같은 중요한 작업을 수행한다. 이는 커널이 제공하는 기능에 접근하기 위해 사용된다.
  • 호출 방식: 시스템 콜을 호출하면 사용자 모드에서 커널 모드로 전환이 일어나며, CPU가 커널 모드로 전환되어 해당 작업을 수행한다.

주요 차이점


  1. 실행 모드:
    • 서브루틴은 사용자 모드에서 실행된다.
    • 시스템 콜은 커널 모드에서 실행된다.
  2. 기능과 목적:
    • 서브루틴은 일반적으로 프로그램 로직을 구성하고 데이터 처리 작업을 수행한다.
    • 시스템 콜은 운영 체제의 커널 기능을 호출하여 하드웨어 자원 관리 및 시스템 레벨 작업을 수행한다.
  3. 호출 방식:
    • 서브루틴 호출은 단순 함수 호출로 이루어지며, 직접적인 CPU 모드 전환이 필요 없다.
    • 시스템 콜 호출은 사용자 모드에서 커널 모드로의 전환을 필요로 하며, 이 과정에서 CPU 모드 전환이 발생한다.
  4. 오버헤드:
    • 서브루틴 호출은 시스템 콜 호출에 비해 오버헤드가 적다.
    • 시스템 콜 호출은 사용자 모드에서 커널 모드로의 전환과 관련된 오버헤드가 발생한다.

예시로 보는 진행 방식


  1. 서브루틴 호출 예시:
    • 사용자가 printf 함수를 호출한다.
    • printf 함수는 사용자 모드에서 실행되며, 커널 모드로 전환되지 않는다.
  2. 시스템 콜 호출 예시:
    • 사용자가 read 시스템 콜을 호출한다.
    • read 시스템 콜은 사용자 모드에서 커널 모드로 전환된다.
    • 커널은 해당 작업을 수행하고 결과를 시스템 콜로 반환한다.
    • 시스템 콜이 결과를 사용자 프로그램에 반환한다. - 서브루틴과 시스템 콜은 모두 중요한 역할을 하지만, 그 역할과 동작 방식에는 명확한 차이가 있다. 서브루틴은 사용자 프로그램 내의 로직 구성에 사용되고, 시스템 콜은 커널 기능 호출을 통해 하드웨어 자원 관리와 시스템 레벨 작업을 수행하는 데 사용된다.


참고 자료


이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.