숑숑이의 개발일기

Race condition이란?

임계영역(critical section: 공유 메모리에 접근하는 프로그램의 일부)이 두 개 이상의 스레드에 의해 동시에 실행되는 조건으로 정의할 수 있다. 다르게 말해 특정 공유 리소스를 얻기 위해 두개 이상의 스레드가 함께 경쟁하는 조건으로 정의.(동시성 버그, deadlock과 밀접한 연관이 있음) 이는 프로그램의 잘못된 동작으로 이어진다.

 

예시코드

3개의 쓰레드가 공유하는 변수 c의 값을 조정한다.

public class Counter implements Runnable {
    private int c = 0;

    public void increment() {
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            //Auto-generated catch block
            e.printStackTrace();
        }
        c++;
    }

    public void decrement() {
        c--;
    }

    public int getValue() {
        return c;
    }

    @Override
    public void run() {
        //incrementing
        this.increment();
        System.out.println("Value for Thread After increment " + Thread.currentThread().getName() + " " + this.getValue());
        //decrementing
        this.decrement();
        System.out.println("Value for Thread at last " + Thread.currentThread().getName() + " " + this.getValue());
    }
}

발생 원인

1) 불충분한 동기화

여러 스레드 또는 프로세스가 적절한 동기화 없이 공유 리소스에 액세스하면 발생할 수 있음

 

2) 비원자적 작업

여러 단계로 구성되고 단계 사이에서 중단될 수 있는 작업은 비원자적으로 여러 스레드가 공유 리소스에서 비원자적 작업을 수행하는 경우 발생할 수 있음

 

3) 실행 순서에 대한 잘못된 가정

프로그래머가 강제하지 않고 특정 실행 순서를 가정할 때 실제 실행 순서가 다를 경우 발생할 수 있음

 

 

해결 방법

1) 상호배제(Mutual exclusion)

스레드가 공유 변수 또는 공유 스레드를 사용하는 경우 다른 스레드가 동일한 작업을 수행하지 못하도록 배제한다

 

2) 프로세스 동기화(Synchronize the process)

한번에 하나의 프로세스만 공유데이터에 액세스할 수 있도록 한다

 

Java에서는 동기화 기업으로 상호배제(보완된 세마포어)를 구현한 Monitor를 Object 내부에 구현하여 모든 인스턴스에 스레드 동기화를 가능하게 한다. 이렇게 상호배제를 하기 위해서는 synchronized 키워드를 사용할 수 있다. 사용방법

 

공유변수 연산 시 다른 스레드가 끼어들지 못하도록 run 메서드 내부에 동기화 block을 만들었다.

public class Counter implements Runnable {
    private int c = 0;

    public void increment() {
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            //Auto-generated catch block
            e.printStackTrace();
        }
        c++;
    }

    public void decrement() {
        c--;
    }

    public int getValue() {
        return c;
    }

    @Override
    public void run() {
        synchronized (this){
            //incrementing
            this.increment();
            System.out.println("Value for Thread After increment " + Thread.currentThread().getName() + " " + this.getValue());
            //decrementing
            this.decrement();
            System.out.println("Value for Thread at last " + Thread.currentThread().getName() + " " + this.getValue());
        }
    }
}

 

https://velog.io/@gjwjdghk123/RaceCondition
https://easyitwanner.tistory.com/135
profile

숑숑이의 개발일기

@숑숑-

풀스택 개발자 준비중입니다