관리 메뉴

사과하는 제라스

9. Synchronization(동기화)-1 본문

대학 전공 공부/운영체제

9. Synchronization(동기화)-1

Xerath(제라스) 2022. 11. 24. 00:34

목차

    728x90
    반응형

    Race Condition

    : 공유 데이터에 대해 여러 프로세스가 동시 접근 및 변경을 시도하는 상황

     

    -> 이러한 동시 접근 및 변경은 데이터의 일관성(Consistency)을 해침.

     

    Race Condition 예시

    은행의 입출금 문제

    : 1000원의 잔고가 있는데, 여기에 500원 입금, 500원 출금이 동시에 일어남. 결과는?

    입출금 소스코드

    이 소스코드들은 컴파일러에 의해 분해되기에 레지스터 수준에서 봐야함.

    분해된 소스코드. 결과적으로 500이 남게 되었는데 이는 1500이 될 수도 있다. 하지만 둘 다 원하는 결과가 아님!!!!!!

    Critical Section

    : 여러 프로세스들이 공유하는 데이터에 접근하는 Code 영역

    ex. 위 입출금 문제 예제에서는 Balance = Balance + 500; , Balance = Balance - 500;

     

    Race Condition을 방지하기 위해!!!

    한번에 단 하나만의 프로세스가 Critical Section에 진입해야 함.

     

    Critical Section을 가진 프로세스의 Modeling

    Critical Section 문제 해결 알고리즘의 조건 3가지

    1) Mutual Exclusion(상호 배제)

    : 만약 어떤 프로세스가 Critical Section에 진입해 있다면, 다른 모든 프로세스는 진입할 수 없어야 함.

     

    2) Progress(진행)

    : 만약 어떤 프로세스가 Critical Section에 들어가려 한다면, Remainder Section에서 실행 중이 아닌 프로세스들만이 누가 진입할지 결정할 수 있어야 함.(실행 중인 놈들은 빠져있어! 진입하려는 애들끼리의 싸움이다!), 결정은 무한히 연기될 수 없음.

     

    3) Bounded Waiting

    : 프로세스가 Critical Section에 진입 시까지 걸리는 시간에 Limit이 존재해야 함.(계속 기다리는 놈이 생길 수도 있잖아? 걔는 적당히 기다리다가 Limit된 시간이 되면 걔부터 실행시켜주는 거임.)

     

    알고리즘 예시 1

    P0 -> P1이면 해당 알고리즘은 만족하겠지만, 두 프로세스의 수행 순서가 바뀌면 진행이 안되고 무한정 대기해야 하는 경우가 생김.

     

    알고리즘 예시 2

    만약 P0에서 flag[0] = true; 를 실행 후 Context Switching이 되어서 P1을 실행하면 flag[0], flag[1] 둘 다 true가 되어버림.

    그 결과 둘 다 Critical Section에 진입이 불가능해짐.

     

    해결 방법 - Peterson Solution

    -> 앞서 본 두 알고리즘을 복합해서 만든 코드임.

    Critical Section의 3가지 조건을 모두 만족함.

     

    오우 좋네~~~

     

    근데..!! Peterson Solution도 문제가 있음!

    Peterson Solution의 한계

    1) Peterson Solution의 확장이 가능?

    : 즉, 3개 이상의 프로세스에서는 어떻게 구현할 건데...??

     

    2) 확장된 알고리즘의 증명은 어떻게 할 건데?

    : 어떤 경우에도 동작함을 보여줘야 함.

     

    3) 일반적으로 이런 증명은 NP 문제임.

    : 즉, 증명이 되더라도 매우 복잡함.

     

    4) HW로 처리하면 알고리즘이 매우 간단해짐.

    Lock이라는 HW로 해결 가능.

    근데... 이거 HW로 구현하면 비용이 많이 듦.

    -> 어? 이거 Critical Section에 들어가면서 Interrupt를 disable하게 하면 되지 않음?

    -> 아...근데 그거 User 프로그램 수준에서 Interrupt를 컨트롤하는건 바람직하지 않아...

    (시스템 성능, 관리적 시점에서 좋지 못함.)

    + 프로세스가 많아지면 문제가 생길 수 있음.(Scalable하지 않음)

    -> 동기화를 위한 Instruction이 도입됨.

    Synchronization Instruction(동기화 명령)

    : CPU에서 지원하여 원자적으로(Atomically: 명령어가 수행되는 동안 방해받지 않음.) 수행되는 명령어를 이용함.

     

    Mutual Exclusion with Test-and-Set

    Test and Set 명령어를 수행 시에는 어떤 방해도 받지 않음.

    -> Test and Set은 인자로 들어온 값을 True로 바꿔주고 들어왔던 값을 return해주는 역할을 함.

    false 값인 lock이 프로세스를 진행하면 TestAndSet(&lock)은 false를 리턴하고 내부에선 lock값을 true로 바꿈.

    -> critical Section을 진행한 후 lock값을 다시 false로 바꾼 뒤 Remainder Section에 들어감.

     

    Mutual Exclusion with Swap

     waiting 배열에서 실행하려는 i번째 프로세스에 대한 값 waiting[i]를 true로 바꿔주고, while문을 통과

    -> 이때 lock이 true이면 swap 시 lock도 true, waiting[i]도 true되고 이후 critical section 진행하고, lock 다시 false로 바꾸고, remainder section 진행

    -> 근데 만약 lock이 false였다면 swap 결과 waiting[i]가 false가 되어서 while문 빠져나와서 진행 X.

     

     

    이런 Instruction 방식의 한계점

    1) Mutual Exclusion은 해결되지만 Bounded Waiting은 모두 해결되지 않음.(다음에는 어떤 프로세스가 Lock을 가질지와 같은게 정해지지 않음.)

    ∴ 이건 User 프로그램이 제공해야 했음.

     

    2) Bounded Waiting이 주어진 문제마다 조금씩 차이가 있기에 User 프로그램이 제대로 처리하는 것은 기대 hard...

     

    3) 좀 더 포괄적인 동기화 방식이 필요함.

     

    Semaphores(세마포어)

    : 2개의 우너자적 연산을 가지는 정수 변수

    - Wait() or P() : Critical Section에 들어가기 전에 수행됨

    - Signal() or V() : Critical Section을 나와서 수행됨.

    -> 세마포어는 이 2가지의 원자적인 연산에 의해서만 접근됨. + 이 두 연산은 서로 독립적이고, 원자적으로 수행됨.

    (따라서, 하나의 프로세스에서 P를 수행해서 세마포어의 값을 수정하는 동안에는 다른 프로세스에서는 P or V를 수행할 수 없기에 같은 세마포어의 값을 수정하지 못함.)

    세마포어 예시

    세마포어의 구현 - Busy Waiting

    : Critical Section에 진입할 조건이 될 때까지 Loop을 돌며 기다림.

    - 단점

    1) CPU Cycle을 낭비함.

    2) 대기 중인 프로세스 중에서 누가 Critical Section에 진입할지 결정하지 않음.

     

    Busy Waiting 방식의 CPU Cycle 낭비 문제 해결하기 위해 등장한게...!!

    세마포어의 구현 - Sleep Queue

    : 세마포어의 자료구조에 Sleep Queue를 추가하여, 대기 중인 프로세스를 관리함.

    -> 세마포어의 값이 양수가 되어 Critical Section에 진입이 가능하게 되면, Sleep Queue에서 대기 중인 프로세스를 깨워 실행시킴.

    - list: Critical Section에 들어가기를 기다리는 프로세스 리스트.

    - block(): sleep하는 것. 실행 중인 프로세스를 멈추고 다른 프로세스로의 Context Switching 유도함.

    - wakeup(p): 프로세스 p를 실행함.

    세마포어의 종류

    1) Counting Semaphore

    - 세마포어의 값은 범위가 정해져 있지 않음.

    - 초기 값은 가능한 자원의 수로 정해짐.

     

    2) Binary Semaphore

    - 세마포어의 값은 0 or 1임.

    - Counting Semaphore보다 구현이 간단함.

     

    - Binary Semaphore를 이용해서 Counting Semaphore를 구현 가능.

    - Binary Semaphore는 test-and-set과 같은 HW의 도움받아 구현 가능.

    (세마포어는 P, V operation으로 이루어져있는데 얘네는 atomic해야 함. 그래서 이런 HW의 도움을 받아서 구현할 수 있다.)

     

    Binary Semaphore의 구현

    - Test and Set 명령어로 구현함.

    - Semaphore S: 현재 Critical Section에 진입한 프로세스가 있는지 나타냄.(T / F)

     

    P(S)

    - while(test_and_set(&S));

    - S의 값이 return되고 S는 true로 바뀜.

    (즉, S가 false이면 while로 loop안 돌고 바로 Critical Section 진입함. 근데 만약 S가 true이면 while로 계속 loop 도는게지...!)

     

    V(S)

    -  S = false;

    - 진입한 프로세스가 없음으로 바뀌기에 wait()에서 대기 중인 프로세스를 진입 가능하게 함.

    - V가 실행된다는 것은 Critical Section에서 실행 중인 프로세스가 없다는 것을 의미함.

     

    Counting Semaphore의 구현

    이때,

    S1: C를 위한 세마포어

    S2: block / wake up을 위한 세마포어

     

    Semaphore의 구현

    1) 커널이 Single Thread인 경우

    - P / V를 System Call로 실행.

    - 커널 내에서 세마포어의 동작을 구현함.

    - 커널 내의 수행이 Non-Preemptive하므로, 커널에 들어간 것 = Critical Section에 들어간 것.

     

    2) 커널이 Multi Thread인 경우

    - P / V를 System Call로 실행.

    - 커널 내에서 별도로 동기화 작업이 필요함.

    세마포어의 단점

    1) Deadlock이 발생할 가능성이 있음.

    2) P와 V의 연산이 분리되어 있기에 잘못 사용 시에 대책이 없음.

    - High-level 언어에서 동기화를 제공하는 방법이 필요해짐.

    Deadlock

    : 2개 이상의 프로세스들이 끝없이 이벤트를 기다리고 있는 상황으로 그 이벤트는 기다리고 있는 프로세스만이 발생시킬 수 있음.

    P0가 S를 가져가고 P1이 Q를 가져간 상태 - P0에서 Q를 가져가려는데 아직 P1에서 풀어주질 않음, P1에서 S를 가져가려는데 아직 P0에서 풀어주질 않음 - 무한 대기

     

    이런 Deadlock 없는 방법 없음?!!?!?!?!!?!?!?!?!?!

    그래서 나온게...!!

    Monitor

    : High-level 언어에서의 동기화 방법.

    - 한 순간에 하나의 프로세스만 모니터에서 활동하도록 보장.

    - 유저 레벨에서는 P / V 연산없이 Procedure를 호출하는 것만으로도 동기화 해결 가능.

    (세마포어 중 멀티 쓰레드 커널에선 커널 내에서의 동기화도 해야 하므로 P,V를 잘 사용해야 함. 즉, Deadlock을 방지하기 위한 책임이 프로그래머에게 있음. 근데 모니터는 따로 동기화 해결이 필요가 없으니까 얼마나 편하냐~~!?~~!?)

     

    세마포어와 모니터의 차이

    1) 모니터는 Java에서 모든 객체에 기본적으로 제공하지만, C에서는 사용이 불가능함.

    2) 세마포어는 프로그래머가 Mutual Exclusion및 정렬 목적으로 사용 시 Counter 변수값을 지정하는 불편함 있지만,

    모니터는 이런 기능들이 캡슐화(synchronized, wait, notify 등의 키워드)되어 있어서 동기화에 용이함.

    Monitor 코드 예시
    프로세스들이 Queue에 들어가고 각각은 Shared Data를 쓰기 위해operation으로 condition(false 시 wait, true 시 Procedure들 진행)을 확인 후 Procedure를 진행한다.

     

    Monitor 예시: DB의 Transaction

    하나의 트랜잭션이 실행될 때 다른 트랜잭션의 개입으로 인해 값이 바뀌면 트랜잭션이 값을 보장할 수가 없음.

    ∴  트랜잭션의 실행 시 Monitor를 통해 트랜잭션 단위로 반드시 완전히 수행되도록 보장함.

    728x90
    반응형

    '대학 전공 공부 > 운영체제' 카테고리의 다른 글

    11. Memory Management-1  (0) 2022.12.06
    10. Synchronization(동기화)-2  (1) 2022.12.01
    8. Thread  (1) 2022.11.19
    7. IPC(Inter Process Communication)  (0) 2022.11.17
    6. CPU Scheduling  (1) 2022.11.02