-
반응형
주제 내용 스케줄링 - 실행 대기 중인 프로세스 중에서 우선순위가 가장 높은 프로세스를 선택해 CPU에서 실행시킴 스케줄링 방식 - 선점 스케줄링
강제로 CPU에서 실행 중인 프로세스를 비우고 새로운 프로세스 실행
- 비선점 스케줄링
프로세스가 자발적으로 스케줄링 요청컨텍스트 스위칭 - CPU에서 실행 중인 프로세스의 레지스터 세트를 비우고 새로운 프로레스 레지스터 세트를 채우는 동작
- CPU 아키텍처(ARM, x86)에 따라 구현 방식이 다름스케줄링 정책 - 스케줄링 시 어떤 방식과 규칙으로 다음에 실행할 프로세스를 선택할지 결정 스케줄러 클래스 - 5가지 커널 스케줄러 세부 동작을 모듈화한 자료구조이자 인터페이스
- 프로세스는 스케줄러 클래스를 우선순위에 따라 선택할 수 있음런큐 - 실행 대기 중인 프로세스를 관리하는 자료구조
- percpu 타입 변수우선순위 - 유저 공간에서 설정한 nice와 커널 우선순위가 있음 1. 스케줄링이란?
리눅스 시스템이 탑재된 휴대폰이나 라즈베리 파이에서는 동시에 여러 프로그램을 실행할 수 있다. 휴대폰을 보면 다양한 프로그램이 동시에 실행되는 것을 확인할 수 있다. 예를 들면, 웹 브라우저를 실행하면서 음악을 드거나 메신저를 사용하면서 애플리케이션을 다운로드할 수 있다. 사람들은 여러 프로세스들이 동시에 CPU에서 실행된다고 느낄 수 있다. 하지만 CPU는 여러 개의 프로세스를 절대로 동시에 실행할 수 없다. 리눅스 커널을 포함한 다양한 운영체제에서 스케줄링과 멀티태스킹 기법이 생겨난 이유는 CPU는 한순간에 한 개 프로세스의 코드만 실행할 수 있기 때문이다. 이때 여러 개의 프로세스들이 효율적으로 번갈아가면서 CPU에서 실행될 수 있게 규칙을 부여하고 프로세스들을 관리하는 소프트웨어 모듈을 스케줄러라고 말한다. 하나의 프로세스는 CPU에서 실행을 시작하면 계속 CPU에서 실행되는 것이 아니라 실행되다가 잠깐 멈추고 다시 실행되는 방식으로 동작한다. 즉, 프로세스는 CPU를 점유하면서 실행 중인 상태와 실행 대기하는 상태로 계속 바뀌는 것이다. 메모리에 존재하는 여러 프로세스 중에서 실제 CPU에서 실행될 프로세스를 선택하는 일을 스케줄링이라고 한다. 이때 스케줄러는 어떤 프로세스를 어떤 방식으로 선택할지 결정해야 한다. 스케줄링의 동작 방식은 CPU에서 실행하려고 대기 중인 A ~ D 프로세스 중 하나를 선택해서 CPU에서 실행시키는 동작이다. 커널은 프로세스에게 프로세스의 상태를 정해준다. 프로세스는 생성 및 실행된 후 종료될 때까지 상태가 바뀌면서 동작한다. 프로세스가 CPU에서 실행되기 위해서는 실행 대기(TASK_RUNNIUNG) 상태로 바꾼 다음, 커널 스케줄링에 의해 CPU실행(TASK_RUNNING) 상태로 바꿔야 한다. 프로세스는 실행 후 종료될 때까지 이 과정을 자주 반복한다,. 대부분 한 프로세스의 실행 상태가 바뀌는 흐름도를 보면서 분석할 때가 많다. 전체 시스템 관점에서 프로세스의 상태 변화 다이어그램을 살펴보면, 전체 프로세스가 각각 어떤 상태로 실행 중인지 알 수 있다. 원형으로 표시된 A ~ N 은 각각 프로세스를 의미한다. A ~ D 프로세스들을 보면 실행 대기(TASK_RUNNING) 상태에 있다. CPU에서 실행하기 위해 대기 중인 프로세스이다. CPU 실행(TASK_TUNNING) 상태를 보면 'E 프로세스'가 CPU에서 실행 중이다. 다른 관점에서 스케줄링 동작을 다음과 같이 설명할 수 있다.
실행 대기(TASK_RUNNING) 상태에 있는 프로세스 중 하나를 선택해서 CPU 실행(TASK_RUNNING) 상태로 바꿔주는 동작
커널 스케줄링은 프로세스의 상태를 보고 실행 대기 중인 프로세스를 어떤 방식으로 실행할지를 결정한다. 따라서 프로세스의 상태 정보는 매우 중요하다. 대부분 드라이버 코드를 작성할 때 프로세스 상태를 바꾸는 코드를 작성할 필요는 없다. 하지만 커널 스레드의 핸들러 함수를 구현할 때는 프로세스 상태를 바꿔주는 코드를 입력할 때가 있다. 이때 set_current_state() 함수를 써서 프로세스의 상태를 바꿔야 한다.
2. 선점 스케줄링과 비선점 스케줄링이란?
커널에서 지원하는 스케줄링 방식은 다음 테이블과 같이 선점 스케줄링 방식과 비선점 스케줄링 방식으로 나눌 수 있다.
스케줄링 방식 내용 선점 스케줄링 - 실행 중인 프로세스를 강제로 CPU에서 실행 중지
- 새로운 프로세스가 CPU에서 실행
- 선점 스케줄링 시작점
+ 인터럽트 핸들러를 처리하고 난 후 인터럽트가 발생하기 전 코드로 되돌아가기 직전
+ 시스템 콜의 핸들러 함수를 처리하고 난 후 유저 공간으로 복귀하기 직전비선점 스케줄링 - 프로세스가 자발적으로 스케줄링 요청
- 비선점 스케줄링 시작점
+ 입출력(I/O) 동작을 시작할 때
+ 뮤텍스를 획득하지 못하고 휴면 상태에 진입할 때스케줄링이란 용어를 들으면 선점 스케줄링 방식으로 이해한다. 하지만 프로세스의 스케줄링 방식은 선점 스케줄링과 비선점 스케줄링으로 나눌 수 있다.
선점 스케줄링
먼저 선점 스케줄링의 동작 방식을 살펴보자. 선점이란 단어는 보통 영어로 preemptive 혹은 preemption과 비슷한 의미이다. 실전 개발자들은 선점이랑 표현보다 preemption을 더 자주 쓴다. preemptive라는 단어는 뭔가 점유하고 있는 것을 빼앗아 버린다는 의미가 있다. 이 용어를 써서 선점 스케줄링 동작을 정의하면 다음과 같다.
CPU를 점유하면서 실행 중인 프로세스를 스케줄러가 강제로 CPU에서 빼내는 동작
만약 "A라는 프로세스가 선점 혹은 preemption됐다" 라고 하면 스케줄러는 어떻게 동작할까? 다음과 같이 3단계로 세부 동작을 분류할 수 있다.
- 첫째, 스케줄러는 CPU에서 실행 중인 A 프로세스의 의사와 관계없이 강제로 중지시킴
- 둘째, 새로운 프로세스를 CPU에서 실행시킴
- 셋째, 새로운 프로세스가 CPU를 점유하면서 실행을 시작
그러면 선점 스케줄링은 언제 시작할까? 다음 두 가지 상황에서 실행을 시작한다.
- 인터럽트 핸들링 후
- 시스템 콜 핸들링 후
앞에서 소개한 '선점 스케줄링 방식'을 정리하면 CPU에서 실행 중인 프로세스를 빼내고 새로운 프로세스를 CPU에서 실행시키는 것이다. 여기서 한 가지 의문이 생긴다. 그러면 CPU에서 실행 중인 프로세스가 충분히 자신이 하고 있는 일을 마치고 CPU에서 나가면 안 되는가? 물론 CPU에서 실행할 프로세스의 개수가 적거나 모든 프로세스를 커널에서 생성하고 처리한다면 이 방법이 가장 좋을 것이다. 하지만 리눅스 커널은 다양한 애플리케이션을 실행하도록 지원해야 하므로 어떤 프로세스가 실행될지 예측할 수 없다. 그래서 '출처를 알 수 없는' 어떤 프로세스가 자신이 CPU를 쓰고 싶을 만큼 충분히 점유하게 되면 실행 대기로 기다리는 프로세스들이 'CPU를 차지하면서' 실행할 수 있는 기회가 줄어들게 된다. 그 결과, 시스템 응답 속도가 느려질 가능성이 높아진다. 그러면 선점 스케줄링 방식을 적용했을 때 얻는 이점은 무엇일까? 어떤 프로세스가 CPU를 점유하면서 실행하건 강제로 실행 흐름을 중지시킬 수 있기 때문에 실행 대기 상태로 기다리고 있는 프로세스들이 CPU에서 실행될 수 있는 기회를 더 자주 얻을 수 있다. 커널에서는 선점 방식을 적용해서 프로세스가 빠른 응답과 실행이 가능하도록 지원하는 것이다. 만약 휴대폰에서 어떤 애플리케이션을 터치해서 실행했을 때 해당 애플리케이션을 구동하는 프로세스가 더 빨리 실행할 수 있게 된다. 프로세스가 스케줄링을 실행한다. 그래서 스케줄링이 빈번하게 발생하면 프로세스가 순수하게 실행할 수 있는 시간 외에 스케줄링 동작을 위한 커널 코드를 추가로 실행해야 한다. 이 같은 컨텍스트 스위칭이 빈번하게 발생하면 프로세스 입장에서는 오버헤드이다. 너무 잦은 스케줄링은 시스템 응답 속도가 느려지는 효과를 초래한다. 그렇다면 프로세스 입장에서 중요한 동작을 수행 중이다가 선점되면 어떻게 될까? 예를 들어 수학적 알고리즘을 실행 중이거나 디바이스에 정확한 타이밍으로 어떤 값을 써주는 동작이 여기에 해당한다. 이 경우 시스템이나 관련 디바이스 드라이버는 오동작할 수 있다. 그렇다면 선점돼서는 안 될 코드 블록이 있는 경우 어떻게 해야 선점 스케줄링을 비활성화할 수 있을까? 선점됐을 때 문제가 생길 수 있는 중요한 코드 블록은 preempt_disable()과 preempt_enable() 함수를 페어로 호출해서 선점 스케줄링을 비활성화해야 한다.
비선점 스케줄링
비선점 스케줄링이란 자발적인 스케줄링이라고도 한다. 조금 전문적으로 비선점 스케줄링을 정의하자면 "프로세스가 입출력을 시작하면 자발적으로 스케줄리을 요청하는 동작"이라 할 수 있다. 입출력이 끝나면 다시 깨어나 실행 대기 상태로 바꾼 다음 다시 실행을 시작하는 것이다.
프로세스가 파일 I/O를 시작할 때 파일 입출력을 기다려야 하므로 CPU를 사용할 필요가 없다. 이때 프로세스가 자발적으로 스케줄링 요청을 하는 것이다.
반응형