나의 브을로오그으

#12. 세마포어 본문

Computer Science/운영체제

#12. 세마포어

__jhp_+ 2022. 7. 7. 08:34

프로세스 동기화

- Process Synchronization

  * cf. Thread synchronization

- Processes

  * Independent vs Cooperating

  * Cooperating process: one that can affect or be affected by other processes executed in the system

  * 프로세스간 통신: 전자우편, 파일 전송

  * 프로세스간 자원 공유: 메모리 상의 자료들, 데이터베이스 등

  * 명절 기차표 예약, 대학 온라인 수강신청, 실시간 주식거래

 

- Process Synchronization

  * Concurrent access to shared data may result in data inconsistency

 

- Example: BankAccount Problem(은행계좌문제)

  * 부모님은 은행계좌에 입금; 자녀는 출금

  * 입금(deposit)과 출금(withdraw)은 독립적으로 일어남.

(이전 포스팅글 참고)

(공통된 변수를 사용함으로써 동시접근에 의해 잘못된결과가 나옴. 이를 해결하기 위해 세마포어를 사용)

 

프로세스/쓰레드 동기화

- 임계구역 문제 해결(틀린 답이 나오지 않도록)

- 프로세스 실행 순서 제어 (원하는대로) 

 

(세마포어는 동기화 하기 위한 변수 1개와 2개의 동작으로 구성)

 

(세마포어를 사용해 임계구역 문제를 해겼했다. 그렇다면 프로세스 실행 순서는 어떻게 제어해야 할까?)

 

- 일반적 사용 : Ordering

  * sem.value = 0; 

P1 P2
  sem.acquire();
S1 S2
sem.release();  

P1이 언제나 P2보다 선행되려면 다음과 같이 작성

P1이 먼저 실행된다면 정상적임 -> P2가 먼저 실행되면 S2 작업을 하기 전, acquire()를 호출 -> 현재 sem.value = -1이 됨 -> sem.value < 0이므로 block -> context switching 후 S1이 끝나면 sem.release()를 호출 sem.value = 0이 됨. -> sem.value >= 0 이므로 P2는 block해제(queue에서 나옴), S2실행 -> 이렇게 하면

항상 S1 -> S2 -> S1 -> S2 ... 순으로 실행

import java.util.concurrent.Semaphore;

class BankAccount {
    int balance;
    Semaphore sem1;
    Semaphore sem2;
    BankAccount() {
        // semaphore가 2개 필요함 (상호배타, 진행순서를 위한)
        sem1 = new Semaphore(1);  // 상호배타
        sme2 = new Semaphore(0);  // 진행순서
    }
    void deposit(int n) {
        try {
            sem1.acquire();
        } catch (InterruptedException e) { }
        ////////////////////// 임계영역
        int temp = balance + n;
        System.out.println("+");
        balance = temp;
        ////////////////////// 임계영역
        sem1.release();
        ////////////////////// 진행순서
        sem2.release();
    }
    
    void withdraw(int n) {
        try {
            sem2.acquire();
            ////////////////////// 진행순서
            sem1.acquire();
        } catch (InterruptedException e) { }
        ////////////////////// 임계영역
        int temp = balance - n;
        System.out.println("-");
        balance = temp;
        ////////////////////// 임계영역
        sem1.release();
    }
}

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

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

실행 결과 : ++++++++----++++...

이렇게 하면 항상 입금(deposit)이 먼저 일어남.

 

 

이번에는 Parent->Child->Parent->Child 이렇게 세마포어를 사용해 교대로 나오게 하는 방법

import java.util.concurrent.Semaphore;

class BankAccount {
    int balance;
    Semaphore sem;
    Semaphore dsem;
    Semaphore wsem;
    BankAccount() {
    	sen = new Semaphore(1);
        dsem = new Semaphore(0);
        wsem = new Semaphore(0);
    }
    void deposit(int n) {
        try {
        	wsem.release();
            dsem.acquire();
        ///////////////////////// 임계영역
            sem.acquire();
        } catch (InterruptedException e) { }
        int temp = balance + n;
        System.out.println("+");
        balance = temp;
        sem.release();
        ///////////////////////// 임계영역
    }
    
    void withdraw(int n) {
        try {
            wsem.acquire();
        ///////////////////////// 임계영역
            sem.acquire();
        } catch (InterruptedException e) { }
        int temp = balance - n;
        System.out.println("-");
        balance = temp;
        sem.release();
        ///////////////////////// 임계영역
        dsem.release();
    }
}

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

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

실행결과 : +-+-+-+-...

'Computer Science > 운영체제' 카테고리의 다른 글

#14. 기타 전통적 동기화 문제  (0) 2022.08.24
#13. 생산자-소비자 문제  (0) 2022.07.09
#11. 프로세스 동기화  (0) 2022.07.06
#10. 프로세스 동기화  (0) 2022.07.04
#9. CPU 스케쥴링 알고리즘(3)  (0) 2022.07.02