본문 바로가기
CS

[운영체제] Thread - BankAccount 문제

by DenverAlmighty 2020. 7. 27.

멀티 스레드를 이용해 1,000원을 입금하는 부모님 스레드와, 1,000원을 출금하는 자녀 스레드를 생성했다.

어떤 스레드가 먼저 도는지 확인하기 위해 부모님이 입금하면 +를, 자녀가 출금하면 -가 출력되도록 한다.

 

 

//Java BankAcoount practice1
class HelloWorld{
    public static void main(String[] args) throws InterruptedException { 
        BankAccount b = new BankAccount();
        Parent p = new Parent(b);
        Child c - new Child(b);
        p.start();
        c.start();
        p.join(();
        c.join();
        System.out.println("\nbalance = " + b.getBal());
        
    }
}

//Java BankAcoount practice
public class HelloWorld{

     public static void main(String []args) throws InterruptedException { 
        BankAccount b = new BankAccount();
        Parent p = new Parent(b);
        Child c = new Child(b);
        p.start();
        c.start();
        p.join();
        c.join();
        System.out.println("\nbalance = " + b.getBal());
     }
}

class BankAccount {
    int bal;
    void deposit(int n){
        bal = bal + n;
    }
    
    void withdraw(int n){
        bal = bal -  n;
    }
    
    int getBal() {
        return bal;
    }
}

class Parent extends Thread {
    BankAccount b;
    Parent(BankAccount b) {
        this.b = b;
    }
    
    public void run(){
        for(int i = 0; i<100; i++){
            System.out.print("+");
            b.deposit(1000);
            
        }
    }
}



class Child extends Thread {
    BankAccount b;
    Child(BankAccount b){
        this.b = b;
    }
    
    public void run(){
        for(int i = 0; i<100; i++){
            System.out.print("-");
            b.withdraw(1000);
            
        }
    }
}

 

 

실행 결과를 보면 아래와 같다

 

 

/*

Execute1
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------------------------------------------------
balance = 0


Execute2
-------------------++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------------------------
balance = 0

Execute3
----------------------------------------------------------------------------------------------------++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
balance = 0

*/

 

 

실행을 할 때마다 + 와 - 순서가 바뀐다

이것은 운영체제가 Thread에 대해 스위칭 하는데 타이밍에 따라 스위칭이 다르게 일어나기 때문이다.

 

부모님이 100번 입금하고, 자녀가 100번 출금하니 잔액은 0원이어야 맞다.

실행 결과 0으로 맞게 나왔으나 아주 낮은 확률로 0이 아닌 다른 값이 나올 수 있다.

 

 

 

 

 

좀 더 현실에 맞게 입금 딜레이를 줘보자

tmp 라는 변수의 값을 증가/감소 시키고 tmp를 잔액(bal)에 대입하는 방식으로 바뀌었다.

 

 

//Java BankAcoount practice2(+ time delay)
public class HelloWorld{

     public static void main(String []args) throws InterruptedException { 
        BankAccount b = new BankAccount();
        Parent p = new Parent(b);
        Child c = new Child(b);
        p.start();
        c.start();
        p.join();
        c.join();
        System.out.println("\nbalance = " + b.getBal());
     }
}

class BankAccount {
    int bal;
    void deposit(int n){
        int tmp = bal + n;
        System.out.print("+");
        bal = tmp;
    }
    
    void withdraw(int n){
        int tmp = bal - n;
        System.out.print("-");
        bal = tmp;
    }
    
    int getBal() {
        return bal;
    }
}

class Parent extends Thread {
    BankAccount b;
    Parent(BankAccount b) {
        this.b = b;
    }
    
    public void run(){
        for(int i = 0; i<100; i++){
            b.deposit(1000);
        }
    }
}



class Child extends Thread {
    BankAccount b;
    Child(BankAccount b){
        this.b = b;
    }
    
    public void run(){
        for(int i = 0; i<100; i++){
            b.withdraw(1000);
        }
    }
}

 

 결과를 살펴보면 아래와 같다

/*

Execute1
----------------------------------------------------------------------------------------------------++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
balance = 0


Execute2
---------------------------+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------------------------------------------+++++++++++++++++++++++++++
balance = 100000

Execute3
++++-------------------------------------------------------------------------------++++---------------------++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
balance = 100000

Execute4
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------------------------------------------------
balance = 0


bal = 0 이 아닌 이유 
high level language 로는 1줄이지만
Low level language로는 1줄 아님
그 사이에 context switching 일어나면서 오류 생기는거임

*/

 

 

위의 문제와 같은 이유로 실행시마다 +와 - 순서가 바뀌기도 한다.

그런데 이번에는 잔액이 0이 아닌 결과도 있다. 

그 이유는 High level language인 Java에서는 1줄인 코드가 Low level language로 보면 1줄이 아닌 경우에, 실행 도중 context switching 이 일어났기 때문이다. 

 

이를 해결하기 위해서는, 한번에 1 Thread만 common variable(위 코드에서는 tmp)를 업데이트 하도록 해야한다.

즉 코드 한 줄이 atomic하게 되도록 해야한다. 

 

이러한 문제를 임계구역 문제라고 한다.