본문 바로가기

CS/운영체제

[씨면기작] 프로세스의 문맥교환(Context Switching)에 대해서 설명해주세요.


 해당 글은 저의 주관이 가득 섞인 내용입니다. 특히 질문한 이유, 면접관의 의도 등은 개인적인 생각임을 밝힙니다.  


(0) 시간이 없어서 죄송해요 전체 글을 못읽겠어요. 빠르게 원하는 것만 가져갈게요!

프로세스 문맥교환은 인터럽트에 의해 프로세스의 상태가 변화하는 것을 의미합니다. 하지만, 프로세스의 문맥교환은 오버헤드가 크다는 단점이 있습니다. 오버헤드가 큰 이유는 프로세스 제어 블록에 담겨 있는 레지스터 정보를 저장하고 되돌리는 과정에서 커널에 접근해야 하기 때문입니다. 이러한 오버헤드를 예방하기 위해서  프로세스의 상태를 중단과 재시작을 추가했습니다. 이를 통해 입출력과 같은 시간이 오래 걸리는 과정에서 프로세스의 상태를 중단으로 만들어 해당 입출력이 완료가 되는순간 재시작하게 되어 유휴 시간을 줄여 최대한 성능을 올릴 수 있습니다. 


(1) 질문한 이유가 뭐예요? 

굉장히 포괄적인 질문입니다. 일단 프로세스라고 콕 찝어서 말을 했고, 그리고 프로세스의 문맥교환에 대해서 설명하라고 질문을 던졌습니다. 사실상 우리는 '프로세스의 문맥교환이요.'라며 답을 하고 싶습니다. 하지만 이전 글에서도 말씀 드렸듯이 돈을 벌기 위해선 우리는 지식을 갖고 있음을 뽐내야할 필요가 있겠죠? 그래야 다른 사람들과 지식 수준이 맞아야 대화도 하고 협업도 하고 이해도 하고 아는척도 하고 모르는거 나오면 공부해서 다시 대화 수준 끌어올리고 할 수 있겠죠? 절대 아는척은 해선 안됩니다. 왜냐하면 실제로 금방 들통나버려요. 자 어쨌든 엄청 포괄적인 질문입니다. 그렇다면 우리는 열심히 포장해서 설명을 해야겠죠?

저는 프로세스의 문맥교환에서 중요한것은 '오버헤드가 심하다' 이를 해결하기 위해서 어떤 방법이 있다. 정도로 설명하면 될 것같습니다. 뭐 실제로 프로세스의 문맥교환은 준비 상태가 있고요, 실행을 하고요 대기도 하고요 중단도 하고요를 설명하라고 던진 질문은 아니기 때문이라는 생각이 들었습니다. 그래서 아래와 같은 글을 준비했습니다.


이전에도 설명했지만, 실제로 프로세스 하나가 계속해서 동작하는 것이 아닙니다. 여러 프로세스가 계속해서 상태가 변화하면서 동작을 이어나갑니다. 이러한 과정을 프로세스 문맥교환(Context Switching)이라고 하는데요. 여기서 중요한 점은 문맥교환이 어떤 상황에 발생하냐 입니다. 문맥교환이 발생하는 원인은 인터럽트(Interrupt)입니다. 특히 현재 실행하는 프로세스와 별도로 외부에서 이벤트가 일어나게 된다면 인터럽트가 발생하게 됩니다.

📢 인터럽트의 종류는 두가지로 말씀드릴 수 있습니다.

첫번째, 입출력 인터럽트(Input Output Interrupt)입니다. 입출력 동작이 발생했음을 확인하고, 이벤트를 기다리는 프로세스를 준비 상태로 바꾼후 실행할 프로세스를 결정합니다.

두번째, 클럭 인터럽트(Clock Interrupt)입니다. 현재 실행중인 프로세스의 할당 시간을 조사해 실행중인 프로세스를 준비상태로 바꾸고 다른 프로세스를 실행상태로 바꿉니다.



이런 인터럽트를 겪으면서 프로세스는 문맥교환을 하게되는데, 사실상 이게 좀 큰 오버헤드를 가져다줍니다. 오버헤드란 그렇게 생각하시면 될 것같습니다. 교통비가 많이 든다고 생각하시면 됩니다. 잠깐 왔다 가는 것이 아니라 꽤나 긴 여행을 한다고 생각하시면 됩니다. 그러니까 러시아 횡단을 시도하는 것입니다. 즉, 교통비가 많이 발생하는 이유는 이렇습니다.

📌레지스터 상태를 저장하고 이전에 상태를 돌려놔야 합니다. 문맥 교환 과정에서 현재 실행 중인 프로세스의 레지스터 상태를 저장하고, 다음에 실행할 프로세스의 레지스터 상태를 돌려놓습니다. 이 과정에서 시스템 호출(System call) 커널 모드에 접근을 해야합니다. 그래서 오버헤드가 발생합니다.

📌그리고, 가상 메모리 매핑을 해야합니다. 다음 실행할 프로세스의 가상 메모리를 물리 메모리에 매핑해야 하기 때문에 이 과정에서 페이지 테이블(Page Table) 메모리 매핑과정에서 설명드립니다. 그리고 TLB를 업데이트해야 하므로 오버헤드가 발생합니다.

📌마지막으로, 현재 실행 중인 프로세스의 캐시 메모리에 있는 데이터를 무효화하고, 다음에 실행할 프로세스의 캐시 메모리를 적재해야합니다. 이 과정에서 캐시 미스(Cache miss)가 발생하게 되어 페이지 스왑인 아웃을 하게되어 오버헤드가 발생합니다.

이러한 이유로 운영체제는 오버헤드를 줄이기 위해 최대한 문맥교환이 발생하지 않도록 노력을 마아아아아않이 합니다. 그래서 이러한 문제를 해결하기 위해 상태를 늘리게 됐습니다.


📢  야 상태를 늘려보자

중단과 재시작 상태를 추가합니다. 프로세스의 상태가 준비 실행 대기의 상태만 사용하게 될 경우 입출력 동작이 연산보다 느려 시스템 대부분이 유휴상태가 되어 성능상 문제가 발생하게 됩니다.

왜? 입출력 동작이 연산보다 느리게 되어 시스템이 유휴 상태가 되는 것일까요? 우리는 항상 이러한 것에 의문을 갖고 하나하나 검토를 해봐야합니다. 이러한 습관이 실제 현업에서 중요하더라고요. 무작정 복사 붙여넣기 해서 일단 되게 만들어가 아니라! 왜 나는 이것을 써야하는가? 다른 방안은 없는가? 를 생각하는 과정이 매우 필요했습니다. 지금도 항상 그렇게 하려고 노력을 하고 코드를 고치고 있습니다.

왜냐하면, 준비와 실행 상태만 사용되는 경우에 프로세스는 연산을 수행할 준비가 되었을때만 CPU를 할당받고 실행합니다. 하지만 프로세스가 입출력(I/O)작업을 수행할 때는 CPU에서 대기 상태가 되며, 이는 시간이 오래 걸리는 외부 이벤트 응답을 기다리고 있는 것입니다.

예를 들어, 네트워크를 통해 데이터를 전송하는 경우 CPU는 외부 자원의 응답을 기다리는 동안 대기 상태에 있어야하고, 이로 인해서 CPU는 유휴상태가 됩니다. 따라서 입출력 동작이 연산보다 느려 CPU가 대기 상태에 들어가는 시간이 늘어나게 됩니다.

그래서 위 상태(준비와 실행)만 갖고 있다면 성능상 문제가 발생하게 되는 것입니다. 이러한 상황을 예방하기 위해서 해결방은으로 프로세스 중단 상태를 추가한 것입니다.

프로세스가 중단이 되면서 특정 이벤트의 발생을 기다리게 됩니다. 그리고 어떠한 이벤트 우리가 방금 말한 네트워크를 통해 데이터 전송을 마쳤을 때 즉시 실행상태로 바꾸게 되며 최대한 성능을 올릴 수 있는 것입니다.


이와 같이 프로세스의 문맥교환에 대해서 설명할 수 있습니다. 하지만, 면접관 앞에서 이렇게 장황하게 설명할 기회는 길게 주어지지 않겠죠? 그래서 아주 멋지게 줄이고 줄여서 핵심만 탁탁 귀에 얹히도록 만들어야합니다.

프로세스 문맥교환은 인터럽트에 의해 프로세스의 상태가 변화하는 것을 의미합니다. 하지만, 프로세스의 문맥교환은 오버헤드가 크다는 단점이 있습니다. 오버헤드가 큰 이유는 프로세스 제어 블록에 담겨 있는 레지스터 정보를 저장하고 되돌리는 과정에서 커널에 접근해야 하기 때문입니다. 이러한 오버헤드를 예방하기 위해서  프로세스의 상태를 중단과 재시작을 추가했습니다. 이를 통해 입출력과 같은 시간이 오래 걸리는 과정에서 프로세스의 상태를 중단으로 만들어 해당 입출력이 완료가 되는순간 재시작하게 되어 유휴 시간을 줄여 최대한 성능을 올릴 수 있습니다. 


(2) 해당 질문을 한 면접관의 의도는 무엇일까요?

프로세스 문맥 교환에 대해서 어떤 문제가 있는지 그리고 어떤 해결방안으로 문제를 해결했는지를 알아보려는 생각 인것 같습니다. 그래서 위에 말씀드린 것과 같이 상태를 추가하면서 문제를 예방했지만 사실상 이게 메인입니다. 컴퓨터 공부를 하면서 대부분 사람들이 한번은 들어봤을 그 이름이 나오게 됩니다. 스레드인데요? 실제로 스레드는 프로세스의 오버헤드를 줄일 수 있는 부분을 많이 갖고 있습니다. 그래서 

다음 씨면기작은 🔜스레드(Thread) 입니다.