반응형

프로세스 동기화

6.1 Background

  • Cooperating processes
    • 프로세스들끼리 서로 영향을 주고 받는 것들에 대해 알아봄
    • 스레드가 logical address space를 공유하거나, 메시지를 주고 받는 것(share memory or message-passing)
    • cuncurrent하게 공유된 데이터에 접근할 떄에는 data inconsistency 를 고려해야함
    • concurrent하게 실행되는 프로세스들이 정해진 순서로 실행(orderly execution)되도록 보장해주어야 데이터의 consistency 가 유지됨
  • The integrity of data shared by several processes(or threads)
    • Concurrent execution : 프로세스 실행 중에 갑자기 interrupt가 발생해서 멈출 수 있고, 이후 다른 프로세스에 의해 작업이 재개될 수 있음. 근데 공유하는 데이터가 존재한다면 데이터 동기화에 문제가 발생함
    • Parallel execution : 여러 개의 프로세스가 동시에 분리된 CPU에서 실행하게 되면 마찬가지로 동기화 문제가 발생함

생산자-소비자 문제 상황으로 살펴보기

  • P, Q에서는 buf(shared data or queue)를 두고 통신함
  • Parallel할 때에는 P와 Q 통신 시 동시에 서로 버퍼를 읽고 쓰려고 하니까 문제가 될 것이 예상가능함.
  • 하지만 Concurrent 상황에서는 왜 문제가 될까? 논리적으로 봤을 때에는 생산자가 CPU를 할당받아 버퍼를 쓸 동안 소비자는 접근하지 않을 것 같은데 왜 동기화 문제가 발생하는지 살펴보세.
    • buffer에 아이템이 몇 개 있는지 알 기 위해서 새로운 아이템이 추가될때마다 1씩 증가, 소비될때마다 1씩 감소하는 상황이라고 가정
    • 코드 : 스레드는 data와 code를 공유하니까 sum 전역변수도 공유함
    • 실행결과 : 어떨 땐 제대로 2만이 찍히는데, 항상 그렇지는 않은 것을 볼 수 있음
    • 새로운 상황 - 스레드 1에서는 count++, 스레드 2에서는 count—를 해보자. 0이 왜 나올떄도 있고 안나올떄도 있을까?
      • count++과 count—은 내부적으로 아래처럼 3개의 명령어가 세트로 실행됨. 명령어 실행 전과 실행 후에 context switch가 발생할 경우는 괜찮은데 만약 중간에 발생한다면?
      • count = 5인 상황에서 좌측 스레드에서 register + 1 명령어가 수행되어 register = 6인 상황에서 컨텍스트 스위치 발생하여 우측 count - 1을 실행하여 count = 4가 됨. 그런데 다시 좌측 스레드가 resume 되면서 count = 6가 실행되어 버린다면?
      • 원래 5가 되길 기대했는데, sum이 6이 된 상황 (4, 5, 6 중 하나가 되는 상황임!) 어디서 context switch가 발생하냐에 따라서 수행 결과가 달라질 수 있음
      • Untitled
  • Race Condition(경쟁상태, 경쟁상황) : 여러 개의 프로세스(혹은 스레드)가 어떤 데이터를 공유하고 있을 때 실행 결과는 어떤 순서에 따라 명령이 실행되냐에 따라 달라질 수 있는 상황
  • Race condition을 해결할 수 있는 방법
    • synchronization : 특정 시간에 오직 하나의 프로세스만 공유 데이터에 접근하게 함
  • 6.6 연습문제 Race condition의 대표적인 상황 : 입금(deposit)과 출금(withdraw) - deaklock 부분에서 더 자세하게 다룸
  • 6.7 연습문제 : push and pop에서 어떤 데이터가 경쟁 상태에 놓이는가? 어떻게 경쟁 상태를 해소할 수 있는가? (해결방법 아직 안배움!)

6.2 The Critical Section Problem (임계 영역 문제)

  • 경쟁 상태(race condition)을 해결하는 문제를 The Critical Section Problem(임계영역 문제)로 정의함
    • N개의 프로세스가 있을 때 어떤 코드 영역을 critical section(임계영역)이라고 칭함
    • 프로세스들이 어떤 데이터를 공유하는데, 이 데이터를 access, update 한다면 이 데이터를 critiacal section이라 부름
    • 해결 개념 : 어떤 프로세스가 critical section을 실행하고 있을 때는 다른 프로세스들이 접근하지 못하게 하자
  • code를 네 가지 영역으로 나눔
    • entry-section : C-S에 진입하는 코드 영역으로, C-S 진입을 위해 permission을 요청함
    • critical-section : 아까 count ++을 하기 위해 내부적으로 3개의 어셈블리 코드가 실행되었음. 이 3개의 코드를 하나의 덩어리로 만들어서 중간에 context switch가 발생하지 않도록 하기 위한 단위 묶음으로 보면 됌
    • exit-section : C-S에서 나오는 영역
    • remainder-section : C-S 가 아닌 나머지 영역
  • CSP 임계 영역 문제 해결을 위한 3가지 요구사항(전제조건)
    • Mutual Exclusion(상호배제) - 이건 무조건 해결해야함 : 어떤 프로세스가 C-S에서 실행중일 때 다른 프로세스는 C-S에 접근할 수 없음 (단, 상호배제를 하게 되면 데드락과 기아상태가 발생할 수 있음)
    • Progress (avoid deadlock, 데드락) : 어떤 프로세스가 C-S에 있을 때, 모든 프로세스들이 C-S 진입이 무한대로 연기되는 상황이 발생(deadlock)하면 안된다 → 크리티컬 세션에 진입한 애들이 하나도 없음
    • Bounded Waiting (avoid starvation, 기아상태, 왕따) : Bounded Waiting(한정 대기)를 통해 기아 상태 발생을 방지함. Pn이 우선순위에 자꾸 밀려서 평생가도 C-S에 진입하지 못함 (데드락이랑 비슷한거 아닌가..?) 그래서 대기 시한을 한정시킴
    • 여러 가지 해결방법이 있지만 위 세가지 조건을 만족하는 구현 방법은 어렵기 때문에 현실에서는 적당한 타협을 함
  • 경쟁 상황(Race condition)이 발생하지 않게 하는 방법
    • single-core 환경에서의 간단한 해결방법 : interrupt가 발생하지 않도록 함. 단, 복잡한 상황에서는 사용할 수 없음. core가 여러 개 있는 multiprocessor 상황에서는 시스템 효율이 굉장히 떨어지기 때문에 사용이 어려움 → 싱글코어여도 스레드는 여러개일 수 있다! 아마 하나의 프로세스에 하나의 스레드를 가정해버린걸까!! 여튼 사용하지 않는 방법이다!!
    • 단순한 해결방법은 실 사용이 어려우니 크게 두 가지 측면에서 고려를 해보자
      • preemptive kernels(선점형, cpu 자원을 할당받는 프로세스를 다른 프로세스가 강제로 멈출 수 있음) : 프로세스가 언제든지 선점당할 수 있으므로 동기화 문제가 반드시 발생하므로 다루기 까다롭지만 훨씬 효율적임
      • non-preemptive kernels(비선점형) : 현재 cpu를 할당받은 프로세스가 스스로 물러나기 전 까지 그 cpu를 쓰게 해주니까 context switch가 발생하지 않고, 경쟁 상황이 발생할 일이 없음. 하지만 비선점형은 성능이 느리므로 현대적인 상황에서는 잘 사용하지 않음. 경쟁 상태라는 문제를 발생시키기는 하지만 선점형 커널을 많이 사용함 (해당 문제를 해결하는 방향을 선택함) → 여튼 비효율적이라 요즘 안씀

동기화 문제의 해결책

지금까지 동기화 문제가 발생하는 상황을 이해했으니, 이제 해결 방법을 알아보자.

6.3 Peterson’s Solution

  • 임계 영역 문제의 소프트웨어 해결 방법
    • Dekker’s 알고리즘 : 2개의 프로세스로 문제를 해결함 (6.13 연습문제 참고)
    • Eisenberg and McGuire’s 알고리즘 : n개의 프로세스와 n-1의 작은 한정 대기 시간을 갖는 알고리즘 (6.14 연습문제 참고)
    • Bakery 알고리즘 : 유명한 알고리즘으로, 레슬리 램포트(Ramport)가 만들었는데 책에서 다루지는 않음
    • Peterson’s 알고리즘 : 임계 영역 문제를 소프트웨어적인 방법으로 해결한 클래식하고 안전한 방법임. 다만 게런티는 없음. load 와 store 아키텍처에서 발생하는 문제임 (? 뭐라하시는지 못들음)
  • Peterson’s 알고리즘
    • 2개의 프로세스가 임계영역(critical section)과 non-임계영역을 왔다갔다함 (나중에 n개의 프로세스로 확장도 가능함)
    • 개념적인 설명
      • 프로세스 P와 Q는 절대 동시에 CPU 자원을 할당받지 않아야함
      • P가 자원을 할당받을 경우 turn = Q, 그리고 flag에 깃발을 꽂음. 이런 상태일 경우 Q 프로세스는 대기함
    • 간단히 구현해보기
      • 위에서 Peterson 알고리즘을 적용하기 전에 Producer count++, Producer count—를 했을 때에는 0가 항상 보장되지 않았음!
      • 실행해보자 → 알고리즘을 적용하지 않았을 때 보다 실패 케이스가 확연히 줄긴 했지만 종종 동기화 문제가 발생함! 왤까?
      • 이 알고리즘도 완벽하다는 게런티가 없음. 기계어 레벨로 생각하지 않으면 이 구조를 이해할 수 없음 → entry section에서 permission을 얻는 과정 중간에 context switch가 일어난다면? 이 과정이 제대로 되지 않으니 Peterson 알고리즘이 제대로 동작하지 않는 것
    • 그럼에도 불구하고 peterson 알고리즘을 공부하는 이유는 임계영역문제(CSP)를 이론적으로 해결한 소프트웨어 알고리즘이기 때문임
      • 강아지 산책의 개념으로 깃발 꽂고 차례를 주고 받는 것은 개념적으로 완벽하고 증명 가능함. CSP 해결을 위한 세 가지 요구사항(상호배제, progress, bounded waiting)을 모두 충족함
      • Mutual exclusion(상호배제) 증명
      • Progress를 만족하기 때문에 deadlock이 걸리지 않음
      • 한정대기(bounded-waiting)도 가능하기 때문에 starvation(기아상태)가 발생하지 않는 것도 증명 가능함

6.4 Hardware Support for Synchronization

  • Hardware-based 해결 방법
    • 살펴보니까 소프트웨어 레벨에서만 해결하는 건 어려울 것 같음! Hardware 명령어 자체를 CSP를 해결하는 데 지원을 해주자
    • 세 가지 오퍼레이션
      • memory barrier or fences
      • hardware instructions : 하드웨어 레벨에서 atomic한 기능을 보장함
      • atomic variables : application 레벨에서는 하드웨어 레벨에서 지원하는 명령어(compare_and_swap())를 통해 atomic variables를 만들 수 있음
  • Atomicity(원자성) : 원자적 동작(atomic operation)이라 함은 더 이상 쪼갤 수 없는, 중간에 interrupt를 걸 수 없는 단위의 operation을 함
    • 어떤 명령어 자체를 atomic한 명렁어로 만듬
  • 두 가지 타입의 개념적 atomic 명령어
    • test_and_set()
    • compare_and_swap()
  • Atomic Variable
    • 하드웨어 레벨에서 제공해주는 compare_and_swap() 명령어를 통해 application 레벨에서 atomic variable를 만들 수 있음
    • atomic variable이 제공하는 것
      • basic data type(integer, booleans 등)에 대한 atomic operations 만들 수 있음
      • atomic operation을 만들어서 상호배제(mutual exclusion) 할 수 있음
      • 경쟁 상태(race condition)에서의 single variable
  • Java로 atomic variable을 이용하는 방법에 대해 이해도를 높이자 (참고로 atomic variable을 구현하는 것은 너무 low 레벨이라 다루지 않음)
    • Java로 Peterson’s 알고리즘을 구현해도 경쟁 상태(race condtion)에 놓이기 때문에 결과값이 때때로 달라짐 (예제는 P에서 count++, Q에서 count—)
    • Java에서 제공하고 있는 Atomic Variable를 사용해보자! (결국엔 얘도 기계어 레벨로 내려가보면 compare_and_swap을 활용한 것) → 결과를 실행해보니 0이 항상 보장됨! ==하드웨어의 도움을 받아서 피터슨 알고리즘 적용하면 갓벽함!

정리

  • 공유된 자원에 여러 개의 프로세스가 동시에 접근하는 것을 경쟁 상황(race condition)
  • 공유된 자원에 접근하는 코드 영역을 Critical Section이라 하였고, 이를 보호/동기화하는 방법으로 Synchronization 을 함
  • C-S에 진입하기 위한 entry section, 빠져나오기 위한 exit section, 그리고 임계 영역이 아닌 remaining section으로 나뉨
  • 동기화 문제를 해결하기 위해서는 3가지 요구사항을 충족해야함
    • 상호배제
    • progress (데드락 방지)
    • bounded waiting 한정대기 (기아상태 방지)
  • 위 요구사항을 모두 충족하는 알고리즘은 Peterson’s의 알고리즘임 (flag를 이용하여 2개의 프로세스가 티키타카, 물론 N개의 프로세스로 확장 가능함)
  • 피터슨 알고리즘 외에도 여러 알고리즘이 있지만 임계영역 문제를 해결하기 위한 방법으로 너무 복잡함.간단하게 상호배제만 쉽고 간단하게 해결하고 싶음! → 뮤텍스세마포어 그리고 모니터 와 같은 synchronaztion 도구를 많이 사용함!

운영체제_퀴즈_06.pdf


뮤텍스와 세마포어

지난시간 요약

  • CSP (임계영역 문제)를 풀기위해 소프트웨어를 통한 해결방법, 하드웨어를 통한 해결방법을 알아봄
  • 소프트웨어 : 피터슨 알고리즘 (이론적으로 완벽하나 제안된 알고리즘을 그대로 적용 시 여전히 상호배제 X) → 그치만 atomic-variable 쓰면 ㄱㅊ
  • 하드웨어 : test-and-set 과 comswap. comswap을 이용하여 atomic variable 만듬

6.5 Mutex Locks

  • CSP를 풀기 위해 하드웨어 명령어나 피터슨 알고리즘처럼 복잡하지 않고 실제로 사용할 수 있는 고차원의 소프트웨어 툴은 없을까?
    • CSP를 모두 다 해결하면 좋겠지만, 그러기 어려우니 상호배제만 집중 공략해본다.
    • Mutext Locks : locking을 이용! the simplest tools for synchronization. 2개만 지원
    • semaphore : 더 많이 사용되고 N개 지원
    • Monitor : 뮤텍스와 세마포어의 단점을 극복한 방법. 자바에서 나오는 wait, notify 등도 다 모니터 기반임
    • Liveness : 데드락 문제도 해결해줌
  • Mutex Lock
    • mutex : 상호배제(mutual exclusion)를 위함
    • 임계영역을 보호하고 경쟁상황(race condition)을 방지함
    • lock 을 사용하기 때문에 권한을 획득하는 과정(acquire)과 반납(releaes)하는 오퍼레이션과 하나의 변수(available:boolean)이 필요함.
    • 이 과정도 atomically 해야한다. 그렇지 않다면 또 context switch가 발생하면서 상호배제가 또 일어나겠지? 근데 그런거 우리가 고민하지 말자. 그거는 운영체제 커널 만드는 사람들이 고민할 영역임
  • Busy waiting (바쁜 대기)
    • 어떤 프로세스가 임계영역에 들어가기 위해 무한루프를 돌면서 기다림. 멀티프로세싱의 세계에서는 단점임. 무한루프 돌면서 CPU를 잡아먹으니까
    • 그래서 뮤텍스락 구현 시 Busy waiting을 안하게 해야함
  • Spinlock
    • 바쁜대기를 하면서 기다리고 있는 mutext lock을 spinlock이라고 부름. 바쁜대기랑 비슷한 의미임. 그냥 그 상태의 뮤텍스락을 지칭함
    • context-switich 시간을 아낄 수 있음으로 항상 나쁜 게 아니다. 오히려 선호될 때가 있다.
    • 싱글코어 프로세싱에서는 위험하겠지만, 그렇지 않을 경우 더 빠를 수 있다
  • 뮤텍스락 구현
    • 피터슨 알고리즘과 다르게 진입, 퇴장이 좀 더 간결함
    • 대신 피터슨 알고리즘처럼 상호배제, progress(데드락 방지),한정대기(기아 방지) 세 개를 모두 보장하지 않고 딱 상호배제만 지킴
    • 간단한건 뮤텍스락으로 해결 가능
  •  

6.6 Semaphores

  • Semaphores
    • 뮤텍스에서는 2개의 프로세스에서 사용했는데 이제는 N개의 프로세스가 상호배제 가능하게 해보자!
    • 세마포어에서 S는 가용한 리소스의 수(정수)로 초기화
    • 두 개의 atomic 기능이 있는데 하나는 wait() == P() == test, signal() == V()==increment==반납 이라 함
    • wait(), signal() 구현 방법에 대한 소개 (생략)
  • Binary Semaphore
    • 범위가 0과 1 사이므로 mutex lock과 유사하게 동작한다. 그래서 뮤텍스락을 따로 구현할 필요 없음
  • Counting Semaphores
    • 여러 개의 인스턴스를 가진 자원들에 사용할 수 있음. 가용한 자원의 수를 S로 관리
    • 사용법 (리소스가 가용한 개수로 초기화하면 됨)
      • 가용가능한 자원의 수로 S를 초기화함
      • S가 0이되면 모든 자원이 사용중이라는 뜻
      • 음수면 웨이팅큐로 보냄 (왜냐면 내 풀에 가용한 스레드 이상의 요청이 들어온거니까 그 이후 요청은 웨이팅큐로 보내나봄?)
  • 세마포어로 동기화 문제를 해결하기
    • 두 개의 프로세스가 concurrenlty하게 동작중인데 S1 이후에 S2가 실행되게 하고 싶다면, P1과 P2가 동기화 되야함. S1 다음에 시그널을 주고, S2는 대기하다가 실행하고!
  • 세마포어 구현하기
    • 동일하게 busy waiting 문제가 발생할 수 밖에 없다
    • 멀티코어 환경에서 spinlock으로 잘 해결해도 되지만! 일단은 아래처럼 풀어보자
    • 이 문제를 극복하기 위해 wait()와 signal() 를 수정해서 무한대기를 하지 않게 하고 싶다! 우리가 배운 개념으로 충분히 가능함!
      • wait()의 수정 : 무한루프 돌면서 busy waiting을 하는 대신에, 스케쥴러를 이용한다. 이 세마포어가 not positive 하기 때문에 기다려야한다면 자기 자신을 suspend 시키고 waiting queue에 들어간다
      • signal()의 수정 : waiting queue에서 대기하고 있던 프로세스가 resume을 할 수 있게 ready queue로 이동시킴!
      • 커널 레벨에서 구현되어있기 때문에 이런 기계어 레벨까지는 몰라도 되지만 개념은 알아야함!
    • C언어로 바이너리 세마포어 구현해보기
    • C언어로 카운팅 세마포어 구현해보기
      • 근데 실제로 실행해보면 원하는 결과가 아님! 바이너리때는 잘 됐는데?! 왜 이런 결과가 나올 지 생각해보기
      • 동일한 자원(전역변수 sum)에 접근하기 때문에 경쟁 상황이 그대로 발생 == 상호배제 실패!
      • 바이너리 세마포어(뮤텍스인데 스레드가 많을뿐)일 때는 왜 잘됐을까? 스레드가 N개여도 실제로는 대기 큐(링크드리스트)에 순서대로 기다리고 있었기 때문임! 동기화되서 한번에 한 스레드만 실행되는거임

모니터와 자바 동기화

6.7 Monitor

  • semaphores 사용의 어려움
    • 편리하고 효과적이지만 timing error 가 자주 발생함
    • 항상 발생하지도 않고 잡기도 어려운 버그가 발생하게 됨
  • 세마포어 문제의 가장 이해하기 쉬운 예
    • 모든 프로세스가 바이너리 세마포어 뮤텍스를 1로 초기화하고, 아래 순서를 지키지 않으면 CS에 2개 이상의 프로세스가 들어가는 상황이 발생함
      • 각 프로세스는 임계영역(CS)에 들어가기 전에 반드시 wait(mutex) 해야함
      • 그 후에는 signal(mutex) 해야함
  • 세마포어를 사용하며 발생할 수 있는 문제를 어떻게 대처해야할까?
    • 동기화 및 세마포어에 대해 이해도가 낮거나, 의도적으로 잘못된 코딩을 하는 프로그래머에 의해 여러 문제 상황이 발생할 수 있음
    • 프로그래머가 세마포어나 뮤텍스락을 잘못사용했을 때 발생할 수 있는 다양한 타입의 에러를 쉽게 정의해보자
    • 아주 간단한 동기화 도구를 이용해보자!
      • 사람에게 친숙한 언어 (↔ 기계어)를 사용하고
      • monitor 를 사용하자!
  • monitor type?
    • ADT (Abstract data type)으로, 프로그래머에게 mutual exclusion(상호배제)를 지원해주는 하나의 데이터 타입 (ex: 자바의 클래스)
  • Conditional Variables
    • 모니터가 자체적으로 동기화 문제를 풀기에는 부족한 점이 있어서 동기화 메커니즘을 제공해주는 condition 변수를 추가로 도입
  • Java의 Monitors
    • 자바는 모니터 구조를 충실하게 따르고 있기 때문에 자바의 동기화를 이해하면 모니터를 이해할 수 있음
    • 자바에서는 monitor-like 을 제공하여 스레드 동기화를 위해 concnrrency 메카니즘을 구현함
    • 뮤텍스나 세마포어락보다 더 본질적인 락이라는 느낌으로 monitor-lock, intrinsic-lock 이라고 함
  • 자바의 동기화를 이해하기 위한 두 개의 문법
    • synchronized keyword
      • 임계영역에 해당하는 코드블록을 선언할 때 사용하는 자바 키워드
      • 임계영역에는 모니터락을 획득해야 진입 가능
      • 모니터락을 가진 객체 인스턴스를 지정할 수 있음
      • 메소드에 선언하면 메소드 코드 블럭 전체가 임계영역으로 지정됨. 이때, 모니터 락을 가진 객체 인스턴스는 this 객체 인스턴스임
    • wait() and notify() method (각각 wait(), signal()임)
      • java.lang.Object 클래스에 선언된 메서드이므로 모든 자바 객체가 가지고 있는 메서드임
      • 쓰레드가 어떤 객체의 wait() 메소드를 호출하면, 해당 객체의 모니터락을 획득하기 위해 대기 상태로 진입함
      • 쓰레드가 어떤 객체의 notify() 메소드를 호출하면, 해당 객체 모니터에 대기중인 쓰레드 하나를 깨움
      • notify() 대신에 notifyAll() 메소드를 호출하면, 해당 객체 모니터에 대기중인 쓰레드 전부를 깨움
  • 오.. Class 내 static으로 count 변수와 increment() 메서드가 존재했을 때에는 ㄱㅊ찮음 → 이거 코드 잘 붙어와서 설명써놔야겠당!
    • 근데 increment()를 객체 메서드로 만들고 각 스레드에서 카운트 객체를 생성한다면?
    • 각각 스레드의 카운트 객체는 자기 자신의 this를 기준으로 모니터를 하는거임!
    • 객체가 달라지면 모니터가 다 따로 있는 것이기 때문에, 각 스레드 내에서만 동기화되고 스레드 끼리 동기화가 되지 않게 되는거임!
    • 그러면 스레드 생성 시에 같은 객체를 넘겨주면 어떨까? → 그러면 괜찮아즴!
    • 그레서 그냥 this 쓰지말고 빈 object 생성해서 동기화를 하는 것이 낫다.
  • Liveness
    • 우리가 배운 모든 것들(뮤텍스, 세마포어, 모니터)는 상호 배제만 제공해주고, 데드락(progress)나 기아상태를 해결해주지 못함
    • 상호배제 뿐만이 아니라 데드락과 기아상태도 해결하기 위해 새로 나온 방법이 liveness 임
    • 여기서는 두 가지만 deadlockpriority inversion 봅시다!
  • Deadlock
    • 두 개 이상의 프로세스가 영원히 기다려야하는 상황
  • Priority Inversion (우선순위 역전)
    • 높은 우선순위가 있는 프로세스가 낮은 우선순위를 가진 프로세스에게 밀리는 현상
    • 커널 데이터를 읽거나 수정해야하는 데 낮은 우선순위의 프로세스가 이미 점유하고 있어서 높은 우선순위의 프로세스가 접근하지 못하는 것
    • 일반적으로 우선순위 역전 현상은 회피해야함
    • 이걸 해결하기 위해 priority-inheritance 프로토콜을 구현하면 된당
      • 낮은 우선순위의 프로세스와 높은 우선순위의 프로세스의 우선순위를 동등하게 만들어 얼른 처리하고 자원을 반납하게 하는 컨셉

퀴즈

운영체제_퀴즈_07.pdf

반응형