둠치킨
코딩하는 둠치킨
둠치킨

블로그 메뉴

  • 홈
  • 분류 전체보기 (220) N
    • BOJ (173) N
      • 스택 (14)
      • 큐 (5)
      • 덱 (4)
      • 그래프 (30)
      • 배열 (8)
      • 재귀 (12)
      • 브루트 포스 (2)
      • 그리디 알고리즘 (7)
      • 다이내믹 프로그래밍 (13)
      • 백트래킹 (24)
      • 기하학 (4)
      • 트리 (4)
      • 구현 (14)
      • 수학 (3)
      • 맵 (1)
      • 다익스트라 (2)
      • 누적합 (5)
      • 유니온 파인드 (2) N
    • 자료구조 (14)
      • 스택 (3)
      • 큐 (5)
      • 덱 (2)
      • 그래프 (1)
      • 트리 (1)
      • 힙 (1)
      • 정렬 (1)
    • C++ (11)
      • 모두의코드 (2)
      • Effective C++ (3)
      • C++ STL (6)
    • 컴파일러 (1)
    • OS (17)
    • 컴퓨터 구조 (2)
    • Unreal Engine 5 (2)

공지사항

전체 방문자
오늘
어제

인기 글

최근 글

태그

  • BFS
  • boj
  • Bruteforce
  • C
  • C++
  • C++ STL
  • Cache Memory
  • deadlock
  • DFS
  • Effective C++
  • java
  • Mutex
  • next_permutation
  • os
  • Process
  • rotate
  • semaphore
  • spin lock
  • STL
  • STL C++
hELLO · Designed By 정상우.
둠치킨

코딩하는 둠치킨

OS

임계영역(Critical Section) 이란?

2025. 6. 23. 21:25

임계영역(Critical Section)이란?

멀티스레드 혹은 멀티프로세스 환경에서는 여러 실행 흐름이 동시에 동일한 자원에 접근할 수 있다. 이때, 공유 자원을 동시에 수정하거나 읽으면 예기치 못한 결과나 충돌이 발생할 수 있다. 이러한 문제를 방지하기 위해 등장한 개념이 임계영역(Critical Section)이다.

임계영역이란, 공유 자원에 접근하는 코드 영역 중 동시에 하나의 실행 흐름만 진입할 수 있도록 보호되어야 하는 부분을 말한다.


예시

다음은 두 개의 스레드가 동시에 하나의 전역 변수 counter를 증가시키는 코드이다.

#include <iostream>
#include <pthread.h>

int counter = 0;

void* increment(void* arg) {
    for (int i = 0; i < 100000; ++i) {
        counter++; // 임계영역
    }
    return nullptr;
}

int main() {
    pthread_t t1, t2;

    // 두 개의 스레드를 생성
    pthread_create(&t1, nullptr, increment, nullptr);
    pthread_create(&t2, nullptr, increment, nullptr);

    // 스레드가 종료될 때까지 대기
    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);

    // counter 출력
    std::cout << "Final counter: " << counter << '\n';

    return 0;
}
 

위 코드는 두 개의 스레드가 하나의 전역 변수 counter를 동시에 100,000번씩 증가시키는 예제이다. 기대값은 200,000이지만, 실제 실행해 보면 값이 그보다 낮게 나오는 경우가 많다.

그 이유는 counter++ 연산이 다음과 같은 3단계로 구성되어 있기 때문이다.

  1. counter 값을 읽어 옴
  2. 값에 1을 더함
  3. 결과를 다시 메모리에 저장

이러한 작업 도중 두 스레드가 동시에 실행되면, 한쪽 스레드의 증가 연산이 다른 쪽에 의해 덮어씌워질 수 있다. 이처럼 결과가 실행 순서에 따라 달라지는 상황을 레이스 컨디션(Race Condition)이라 하며, 이 연산이 수행되는 영역이 임계영역(Critical Section)이다.

이 문제를 해결하려면 counter++가 수행되는 동안 다른 스레드가 동시에 해당 영역에 진입하지 못하도록 막아야 한다. 즉, 임계영역을 보호하는 동기화 도구가 필요하다.


임계영역을 보호하는 방법

임계영역을 정의한 것만으로는 의미가 없으며, 하나의 스레드만 해당 영역에 진입하도록 만드는 동기화(Synchronization) 도구가 필요하다.

대표적인 동기화 기법

기법설명
뮤텍스(Mutex) 상호배제를 위한 잠금 장치. 한 스레드가 잠금하면 다른 스레드는 대기
세마포어(Semaphore) 제한된 수의 동시 접근 허용. 이진 세마포어는 뮤텍스와 유사
스핀락(Spinlock) 락을 얻을 때까지 반복적으로 검사하며 대기. 짧은 임계영역에 적합
원자적 연산(Atomic Operation) 하드웨어 수준에서 분할 불가능한 연산 제공 (예: std::atomic)
아래 코드는 앞서 제시한 문제가 되는 코드를 pthread_mutex로 보호한 버전. 기대값 200,000이 제대로 나오는게 확인된다.
 
#include <iostream>
#include <pthread.h>

int counter = 0;
pthread_mutex_t lock; // 뮤텍스 객체

void* increment(void* arg) {
    for (int i = 0; i < 100000; ++i) {
        pthread_mutex_lock(&lock);   // 임계영역 진입 전 잠금
        counter++;
        pthread_mutex_unlock(&lock); // 임계영역 종료 후 해제
    }
    return nullptr;
}

int main() {
    pthread_t t1, t2;

    pthread_mutex_init(&lock, nullptr); // 뮤텍스 초기화

    pthread_create(&t1, nullptr, increment, nullptr);
    pthread_create(&t2, nullptr, increment, nullptr);

    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);

    pthread_mutex_destroy(&lock); // 뮤텍스 제거

    std::cout << "Final counter: " << counter << '\n';

    return 0;
}

임계영역과 관련된 개념들

1. 상호배제(Mutual Exclusion)

  • 임계영역의 핵심 조건 중 하나
  • 동시에 하나의 실행 흐름만 임계영역에 진입할 수 있어야 한다

2. 레이스 컨디션(Race Condition)

  • 두 개 이상의 실행 흐름이 임계영역에 동시 진입하면서 예측 불가능한 결과가 발생하는 상황
  • 임계영역이 적절히 보호되지 않았을 때 생긴다

3. 교착상태(Deadlock)

  • 둘 이상의 스레드가 서로의 자원을 기다리며 무한 대기 상태에 빠지는 현상
  • 뮤텍스나 세마포어를 사용할 때 락 획득 순서가 꼬이면 발생할 수 있다

4. 기아(Starvation)

  • 특정 스레드가 계속해서 임계영역에 진입하지 못하고 우선순위에 밀리는 상황
  • 공정성(fairness)을 고려한 락 설계가 필요하다

임계영역을 나눌 때의 고려사항

  • 임계영역은 가능한 작게 유지해야 한다
    → 락을 오래 유지하면 전체 성능 저하, 데드락 위험 증가
  • 공유 자원 접근이 반드시 필요한 부분만 포함해야 한다
  • 락을 중첩하거나 잊지 말고 반드시 해제할 것
저작자표시 (새창열림)

'OS' 카테고리의 다른 글

파편화 (Fragmentation)  (0) 2025.06.24
동기화 객체란?  (0) 2025.06.23
데드락(Deadlock)이란?  (0) 2025.06.23
함수 호출의 리턴 주소는 어떻게 스택에 저장될까?  (0) 2025.06.23
변수들이 메모리에 저장되는 영역  (0) 2025.06.23
    'OS' 카테고리의 다른 글
    • 동기화 객체란?
    • 데드락(Deadlock)이란?
    • 함수 호출의 리턴 주소는 어떻게 스택에 저장될까?
    • 변수들이 메모리에 저장되는 영역
    둠치킨
    둠치킨
    코딩 공부를 위한 코딩 블로그 기록 일기

    티스토리툴바