공유 자원
- 프로세스 혹은 스레드가 공유하는 자원
- 다수의 프로세스 혹은 스레드가 동시에 공유 자원에 접근하는 경우 실행에 문제가 발생
임계 구역
- 공유 자원에 접근하는 코드 중 동시에 실행했을 때 문제가 발생할 수 있는 코드를 임계 구역이라고 함
레이스 컨디션
- 프로세스 혹은 스레드가 동시에 임계 구역의 코드를 실행하여 문제가 발생하는 상황
- 자원의 일관성이 손상되며, 2개 이상의 프로세스 혹은 스레드가 임계 영역에 진입하려는 경우 하나는 작업이 끝날 때까지 대기해야 함
public class RaceCondition {
static int sharedData = 0;
public static void main(String[] args){
Thread thread1 = new Thread(new Increment());
Thread thread2 = new Thread(new Decrement());
thread1.start();
thread2.start();
try {
// 종료 대기
thread1.join();
thread2.join();
} catch (InterruptedException e){
System.out.println(e.getMessage());
}
System.out.println("Final value of sharedData: " + sharedData);
}
static class Increment implements Runnable {
public void run() {
for (int i = 0; i < 1000000; i++){
sharedData++; // 공유 데이터 증가
}
}
}
static class Decrement implements Runnable {
public void run() {
for (int i = 0; i < 1000000; i++){
sharedData--; // 공유 데이터 감소
}
}
}
}
레이스 컨디션을 방지하기 위해선 프로세스와 스레드가 동기화되어야 하며, 동기화를 위해서는 실행 순서 제어, 상호 배제를 준수해야 합니다.
실행 순서 제어
- 프로세스 및 스레드를 올바른 순서로 실행
상호 배제
- 동시에 접근해서는 안 되는 자원에 하나의 프로세스 및 스레드만 접근
동기화 기법
- 실행 순서와 상호 배제를 보장하기 위한 동기화 기법
뮤텍스 락
- 동시에 접근해서는 안되는 자원에 동시 접근이 불가능하도록 상호 배제를 보장
임계 구역에 접근하고자 한다면 반드시 lock을 획득(acquire)해야 하고, 작업이 끝났다면 lock을 해제(release)해야 한다.
public class Mutex {
static int sharedData = 0;
static Lock lock = new ReentrantLock();
public static void main(String[] args){
Thread thread1 = new Thread(new Increment());
Thread thread2 = new Thread(new Decrement());
thread1.start();
thread2.start();
try {
// 종료 대기
thread1.join();
thread2.join();
} catch (InterruptedException e){
System.out.println(e.getMessage());
}
System.out.println("Final value of sharedData: " + sharedData);
}
static class Increment implements Runnable {
public void run() {
for (int i = 0; i < 1000000; i++){
lock.lock();
try {
sharedData++; // 공유 데이터 증가
} finally {
lock.unlock();
}
}
}
}
static class Decrement implements Runnable {
public void run() {
for (int i = 0; i < 1000000; i++){
lock.lock();
try {
sharedData--; // 공유 데이터 감소
} finally {
lock.unlock();
}
}
}
}
}
세마포
- 뮤텍스 락은 하나의 공유 자원을 고려하지만, 세마포어는 3개, 4개의 프로세스 및 스레드까지 특정 자원을 이용할 수 있는 상황에 사용
- 공유 자원의 개수가 남아있을 때만 자원 접근 허용
- 뮤텍스 락과 비슷하게 하나의 변수와 2개의 함수로 구성
- 변수 S : 사용 가능한 자원의 수
- wait() : 임계 구역 진입
- signal() : 임계 구역 진입 후 호출
public class Semapho {
static int sharedData = 0;
static Semaphore semaphore = new Semaphore(1);
public static void main(String[] args){
Thread thread1 = new Thread(new Increment());
Thread thread2 = new Thread(new Decrement());
thread1.start();
thread2.start();
try {
// 종료 대기
thread1.join();
thread2.join();
} catch (InterruptedException e){
System.out.println(e.getMessage());
}
System.out.println("Final value of sharedData: " + sharedData);
}
static class Increment implements Runnable {
public void run() {
for (int i = 0; i < 1000000; i++){
try {
semaphore.acquire(); // 세마포어 획득
sharedData++; // 공유 데이터 증가
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
semaphore.release(); // 세마포어 해제
}
}
}
}
static class Decrement implements Runnable {
public void run() {
for (int i = 0; i < 1000000; i++){
try {
semaphore.acquire(); // 세마포어 획득
sharedData--; // 공유 데이터 감소
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
semaphore.release(); // 세마포어 해제
}
}
}
}
}
조건 변수
- 동기화 기법 중 하나
- [조건 변수] : 실행 순서 제어를 위한 동기화 도구로 프로세스나 스레드의 실행 순서를 제어
- wait() : 호출한 프로세스 및 스레드의 상태를 대기 상태로 전환
- signal() : wait()로 일시 중지된 프로세스 및 스레드의 실행을 재개하는 함수
- wait() : 호출한 프로세스 및 스레드의 상태를 대기 상태로 전환
- signal() : wait()로 일시 중지된 프로세스 및 스레드의 실행을 재개하는 함수
모니터
- 공유 자원과 그 공유 자원을 다루는 함수로 구성된 동기화 도구
- 프로세스 및 스레드는 공유 자원에 접근하기 위해 반드시 정해진 공유 자원 연산(인터페이스)를 통해 모니터로 진입해야 함
스레드 안전
- 멀티 스레드 환경에서 어떤 변수나 함수, 객체에 동시 접근이 이루어져도 실행에 문제가 없는 상태
교착 상태
- 일어나지 않을 사건을 기다리며 프로세스의 진행이 멈춰 버리는 현상
- 4가지 발생 조건(상호 배제, 점유와 대기, 비선점, 원형 대기)을 모두 만족해야 발생
상호 배제
- 한 번에 하나의 프로세스만 해당 자원을 이용 가능하기 때문에 발생
- 한 프로세스가 사용하는 자원을 다른 프로세스가 사용할 수 없음
점유와 대기
- 할당받은 상태에서 다른 자원을 할당받기를 기다림
비선점
- 해당 자원을 이용하는 프로세스의 작업이 끝나야만 자원을 이용할 수 있음
원형 대기
- 서로 점유한 자원을 할당받기 위해 원의 형태로 대기
교착 상태 해결 방안
- 발생 조건에 부합하지 않도록 자원을 분배하는 방식으로 예방할 수 있음
- 교착 상태의 위험이 있다면 자원을 할당하지 않는 방식으로 회피할 수 있음
- 교착 상태를 검출한 후 회복할 수 있음
교착 상태 예방
- 교착 상태를 발생시키는 4가지 필요 조건 중 하나를 충족하지 못하게 하는 방법
- 모든 자원에 번호를 매기고 오름차순 할당 등
- 모든 자원에 번호를 매기고 오름차순 할당 등
교착 상태 회피
- 교착 상태를 한정된 자원의 무분별한 할당으로 인해 발생하는 문제로 정의
- 이를 발생하지 않도록 하는 방법, 자원이 많다면 위험 증가
교착 상태 검출 후 회복
- 발생을 인정하고 처리하는 사후 조치
- 자원 선점을 통해 회복, 강제 종료