병렬 처리에서 발생하는 Race Condtion과 Mutual Exclusion

dykwon·2023년 11월 22일
0

Race Condition

"Race condition"이란 컴퓨터 과학과 소프트웨어 엔지니어링에서 발생하는 문제로, 시스템의 출력이 특정 순서나 타이밍에 의존할 때 발생합니다. 이는 병렬 처리나 동시성을 다루는 시스템에서 흔히 볼 수 있는 현상

Race Condition 예시

상황: 은행 계좌에 100달러가 있고, 두 개의 다른 트랜잭션이 동시에 발생합니다.

  1. 트랜잭션 A: 계좌에서 50달러를 인출합니다.
  2. 트랜잭션 B: 계좌에서 90달러를 인출합니다.

이상적인 시나리오:

  1. A가 먼저 실행되어 50달러를 인출하고, 계좌 잔액은 50달러가 됩니다.
  2. 이후 B가 실행되어 90달러를 인출에 실패합니다.

Race Condition 시나리오:

  1. A와 B가 거의 동시에 실행됩니다.
  2. 두 트랜잭션이 계좌 잔액을 동시에 확인할 때, 두 경우 모두 100달러라고 판단합니다.
  3. A와 B가 각각 50달러와 90달러를 인출하려고 시도합니다.
  4. 만약 동시성을 제어하는 메커니즘이 없다면, 두 트랜잭션은 모두 성공적으로 실행되어 총 140달러가 인출됩니다.

Race Condition의 핵심 요소

  1. 동시성: 여러 프로세스나 스레드가 동시에 실행됩니다.
  2. 공유 자원: 이러한 프로세스나 스레드가 공유하는 자원(예: 변수, 파일, 데이터베이스 레코드)이 있습니다.
  3. 비동기적 실행: 프로세스나 스레드의 실행 순서가 예측 불가능하며, 시스템에 의해 동적으로 결정됩니다.

Critical Section (임계 구역)

정의: 여러 스레드가 데이터를 공유할 때, 그 데이터에 접근하는 코드의 일부분을 '임계 구역'이라고 합니다. 한 스레드가 임계 구역에 있는 동안 다른 스레드는 그 구역에 접근해서는 안 됩니다.
중요성: 임계 구역 관리는 데이터의 일관성과 무결성을 유지하는 데 필수적입니다. 잘못 관리되면 데이터 충돌, race condition 등의 문제가 발생할 수 있습니다.

Mutual Exclusion (상호 배제)

정의: 상호 배제는 한 번에 하나의 스레드만이 특정 임계 구역에 접근할 수 있도록 보장하는 개념입니다.
목적: 이는 여러 스레드가 동시에 공유 데이터에 접근하는 것을 방지하여 데이터의 일관성을 유지하는 데 중요합니다.

뮤텍스(Mutex):

Mutex는 Mutual Exclusion(상호 배제)의 약어로, 한 번에 하나의 스레드 또는 프로세스만 공유 자원에 접근할 수 있도록 하는 동기화 기법입니다.
뮤텍스는 주로 크리티컬 섹션(Critical Section)에 접근하는 스레드 간의 경쟁 조건을 방지하는 데 사용됩니다.
뮤텍스는 잠금(lock)과 해제(unlock) 연산을 사용하여 공유 자원의 접근을 제어합니다.

세마포어(Semaphore):

세마포어는 여러 스레드 또는 프로세스가 공유 자원에 접근할 수 있는 허용된 수를 나타내는 카운터입니다. 이 카운터는 양수일 수도 있고 음수일 수도 있습니다.
세마포어는 일반적으로 "이진 세마포어(Binary Semaphore)"와 "카운팅 세마포어(Counting Semaphore)" 두 가지 종류로 나뉩니다.

  1. 이진 세마포어: 값이 0 또는 1로 유지되며, 주로 뮤텍스처럼 상호 배제 목적으로 사용됩니다.
  2. 카운팅 세마포어: 값이 0 이상으로 유지되며, 스레드 또는 프로세스의 수를 제한하거나 조절하는 데 사용됩니다.

세마포어는 wait(대기)과 signal(신호) 연산을 사용하여 공유 자원의 접근을 제어합니다.

자바 멀티스레드 프로그래밍에서의 구현

자바에서는 여러 가지 방법으로 임계 구역과 상호 배제를 구현할 수 있습니다:

Synchronized 메소드 또는 블록:

메소드 전체 또는 특정 코드 블록에 synchronized 키워드를 사용합니다.
이 방법은 해당 메소드/블록에 대한 접근을 동기화하여 한 번에 하나의 스레드만 접근할 수 있도록 합니다.

Lock 인터페이스:

java.util.concurrent.locks 패키지의 Lock 인터페이스를 사용할 수 있습니다.
ReentrantLock 클래스는 가장 일반적으로 사용되는 Lock 구현입니다.
명시적인 lock과 unlock 메소드를 제공하여 세밀한 제어가 가능합니다.

Atomic 변수:

java.util.concurrent.atomic 패키지에 있는 클래스들은 원자적 연산을 지원합니다.
이러한 변수들은 race condition 없이 하나의 스레드에 의해 안전하게 읽고 쓸 수 있습니다.

Volatile 키워드:

변수에 volatile 키워드를 사용하면 모든 스레드에 변수의 최신 값을 보장합니다.
이는 변수의 가시성을 보장하지만, 복합 연산에 대해서는 상호 배제를 보장하지 않습니다.

profile
Programmer, who turns ideas into value

0개의 댓글