운영체제 | 스레드 동기화 이슈

Faithful Dev·2025년 1월 25일

컴퓨터 공학

목록 보기
28/81

동기화 이슈(Synchronisation Issue)는 여러 스레드 또는 프로세스가 동시에 같은 자원(예: 메모리, 파일, 데이터베이스 등)에 접근하거나 조작할 때 발생하는 문제이다. 동기화가 제대로 처리되지 않으면 데이터의 무결성이 깨지거나, 프로그램의 동작이 비정상적으로 될 수 있다.


동기화 이슈가 발생하는 이유

  1. 자원 공유:
    • 여러 스레드 또는 프로세스가 하나의 공유 자원(변수, 파일 등)에 동시에 접근할 때, 누가 먼저 작업을 수행할지 명확하지 않음.
  2. 경쟁 상태(Race Condition):
    • 여러 스레드가 동일한 자원에 접근하여 값을 읽고, 수정, 저장하는 과정에서 수행 순서에 따라 결과가 달라지는 상황.
  3. 원자성 부족:
    • 특정 작업이 중간에 다른 작업으로 끼어들면서, 작업 단위(원자성)가 보장되지 않아 데이터가 손상됨.
  4. 비결정적 동작:
    • 병렬 환경에서는 실행 순서가 매번 달라질 수 있어, 실행 결과를 예측하기 어려움.

동기화 이슈의 종류

경쟁 상태(Race Condition)

  • 여러 스레드가 동시에 자원에 접근하고, 그 결과가 실행 순서에 따라 달라지는 현상.
counter = 0

def increment():
	global counter
    for _ int range(1000):
    	counter += 1
        
thread1= threading.Thread(target=increment)
thread2= threading.Thread(target=increment)

thread1.start()
thread2.start()

thread1.join()
thread2.join()
print(counter) # 결과가 2000이 아닐 수 있음
  • 이유: counter += 1이 내부적으로 읽기 → 수정 → 쓰기로 나뉘는데, 두 스레드가 동시에 실행되면 중간 상태가 덮어씌워질 수 있음.

데드락(교착 상태, Deadlock)

  • 두 개 이상의 스레드 또는 프로세스가 서로 자원을 대기하면서, 무한 대기 상태에 빠지는 문제.
  • :
    • 스레드 A가 자원 1을 점유한 상태에서 자원 2를 기다리고,
    • 스레드 B가 자원 2를 점유한 상태에서 자원 1을 기다리는 경우.
  • 해결 방법:
    • 자원을 일정한 순서로 요청(예: 항상 자원 1 → 2 순서로 요청).
    • 타임아웃을 설정해 대기 시간이 초과되면 요청 취소.

라이브락(Livelock)

  • 데드락과 비슷하지만, 프로세스가 계속 자원 상태를 변경하며, 진행하지 못하고 서로 방해하는 상태.
  • 차이점: 데드락은 멈춰 있지만, 라이브락은 계속 실행되나 진전이 없음.

기아(Starvation)

  • 특정 스레드나 프로세스가 자원을 요청했지만, 다른 작업들에 의해 계속 우선순위에서 밀려 자원을 얻지 못하는 상태.
  • 발생 원인:
    • 우선순위 기반 스케줄링에서 낮은 우선순위 작업이 무한 대기 상태가 됨.
  • 해결 방법:
    • 우선순위 상향 조정(Priority Inversion): 대기 시간이 길어질수록 우선순위를 높이는 방식.

비교적 어려운 디버깅

  • 스레드 간의 실행 순서가 매번 달라질 수 있어, 오류가 비결정적(Non-deterministic)으로 발생.
  • 이를 Heisenbugs라고 부르며, 디버깅이 어렵다.

동기화 이슈 해결 방법

뮤텍스(Mutex, Mutual Exclusion)

  • 공유 자원에 한 번에 하나의 스레드만 접근하도록 잠금(Lock)을 설정.
import threading

counter = 0
lock = threading.Lock()

def increment():
	global counter
    for _ in range(1000):
    	with lock: # 뮤텍스 사용
        	counter += 1

thread1 = threading.Thread(target=increment)
thread2 = threading.Thread(target=increment)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(counter) # 항상 2000 출력

세마포어(Semaphore)

  • 특정 자원을 사용할 수 있는 동시 접근 허용 수를 제한.
  • : 데이터베이스 연걸 제한, 네트워크 포트 제한.

모니터(Monitor)

  • 동기화를 위해 뮤텍스와 조건 변수를 조합한 고수준 동기화 도구.
  • 대부분의 프로그래밍 언어에서 기본 제공(Java synchronised, Python Condition).

원자 연산(Atomic Operation)

  • 여러 단계를 하나의 단위로 묶어 중간 상태 없이 실행.
  • :
    • Python의 queue.Queue는 스레드 안전(Thread-safe)한 큐를 제공.
    • C++의 std::atomic 클래스 사용.

읽기-쓰기 잠금(Read-Write Lock)

  • 읽기 작업은 동시에 허용하지만, 쓰기 작업은 단독으로 실행.
  • 적용 사례:
    • 다중 읽기가 빈번한 데이터베이스 환경.

동기화 이슈의 예방 전략

  1. 자원 할당 순서 정의:
    • 모든 스레드가 자원을 일정한 순서로 요청하여 데드락 방지.
  2. 타임아웃 설정:
    • 자원 요청 시 제한 시간을 설정하여 무한 대기 방지.
  3. 경량 동기화 기법 사용:
    • 자주 동기화가 필요한 경우, 무거운 잠금 대신 경량화를 고려(예: Spinlock).
  4. 스레드 수 관리:
    • 필요한 만큼의 스레드만 생성하여 과도한 자원 경합 방지.

정리

  • 동기화 이슈는 경쟁 상태, 데드락, 라이브락, 기아 등 여러 형태로 나타난다.
  • 이를 해결하기 위해 뮤텍스, 세마포어, 원자 연산, 모니터 등 다양한 동기화 기법이 사용된다.
  • 올바른 동기화 도구를 선택하고, 코드 설계를 신중히 하면 동기화 문제를 예방할 수 있다.
profile
Turning Vision into Reality.

0개의 댓글