1. 데이터의 접근
프로세스 동기화에 대한 설명 이전에 컴퓨터 시스템 안에서 데이터가 접근되는 패턴에 대해 간단히 짚고 넘어가겠습니다. 컴퓨터 시스템 어떤 위치에 있던 데이터에 접근하는 방식은 아래와 사진과 같은 패턴을 가집니다.
우선 데이터가 저장된 위치가 있을 것이고, 그 저장된 데이터를 읽어와 연산해서 다시 원래의 저장된 위치에 저장하는 방식을 거치게 됩니다.
여기서 저장된 위치에서 읽어와 연산 후 다시 반영을 하기 때문에 동기화의 문제가 생길 수 있습니다. 만약 데이터를 읽기만 하면, 누가 읽든, 누가 읽던 도중에 다른 프로세스가 읽든 별로 문제가 되지 않습니다.
그러나 데이터를 수정해야 한다면, 누군가 수정할 때 다른 곳에서 수정이 동시에 진행되는 상황 등이 있다면, 어떤 값을 연산 결과에 저장을 해야하는가에 대한 문제가 생기게 됩니다.
위 사진을 통해 더 쉽게 이해할 수 있습니다. 데이터에 접근하는 주체가 하나라면 +1과 -1 연산을 진행하면 최종 값은 원래의 값 그대로 일 것입니다. 그런데 데이터에 접근하는 주체가 여러 개라서, 만약 한 연산에서는 데이터를 읽어가 +1 만큼 증가시키는 와중에 다른 쪽에서는 -1 만큼 감소시키면, 다른 쪽에서 가져간 데이터에는 +1 증가시킨 값이 반영이 되어있지 않기 때문에 데이터에는 -1이 감소된 값이 결과로 저장되게 됩니다.
이런 식으로 여러 주체가 하나의 데이터에 동시에 접근하려고 할 때를 Race Condition 이라고 부릅니다.
2. Race Condition
데이터에 접근하는 여러 주체가 있다면 Race Condition의 가능성이 있습니다. Race Condition은 말 그대로, 경쟁 상태라고 생각할 수 있습니다. 그래서 이 상태를 조율해주는 방법이 필요합니다. 그러기 위해 Race Condition이 생기는 경우를 생각해볼 필요가 있습니다.
만약 여기서 프로세스가 연산의 주체이고 프로세스가 관리하는 메모리 주소 공간이 저장된 위치라고 한다면, 프로세스는 보통 실행 시 자기 주소 공간에 있는 데이터를 읽어 연산을 하고, 그 결과를 다시 자신의 주소 공간에 쓰게 됩니다. 프로세스는 자기 자신의 주소 공간을 접근 할 수 있지만, 각 프로세스들의 주소 공간 중에 일부를 공유해서 접근하는 공유 메모리를 사용하는 방법에서는 문제가 생길 수도 있습니다.
하지만 프로세스의 일반적인 경우라면, 자기 자신의 주소 공간만 접근하기 때문에 Race Condition이나 프로세스 동기화와 관련된 문제가 발생할 일이 없습니다.
중요한 문제는 운영 체제 커널과 관련돼서 생기는 문제들입니다.
프로세스는 본인이 직접 실행할 수 없어 운영체제에게 대신 요청해야 하는 부분들에 대해서는 시스템 콜을 한다고 지난 포스팅에서 설명드렸습니다. 그래서 커널의 코드가 프로세스를 대신해서 실행이 되는데, 여기서 실행된다는 것은 커널에 있는 데이터에 접근하는 것을 의미하기도 합니다.
그래서 만약 커널에 있는 데이터 값을 바꾸려고 읽어들인 상황에서 CPU 제어권을 뺏겨 다른 프로세스에게 CPU가 넘어갔는데 그 프로세스가 시스템 콜을 해서 커널의 데이터에 접근한다면 Race Condition 문제가 생길 수 있습니다.
또한 커널의 코드가 실행 중일때, 인터럽트가 들어올 수 있습니다. 인터럽트를 실행하는 코드도 커널의 코드이기 때문에 커널의 데이터를 건드리게 됩니다.
즉 사용자 레벨에서는 별로 문제가 되지 않던 부분들이 커널 레벨로 들어가게 되면, 운영 체제의 커널에 있는 데이터들은 여러 프로세스들이 동시에 사용할 수 있는 데이터이기 때문에 문제가 생길 수 있는 것입니다.
이처럼 운영 체제에서의 Race Condition 문제가 발생하는 세 가지 경우에 대해 정리해보겠습니다.
3. OS에서의 Race condition
(1) kernel 수행 중 인터럽트가 발생 시
커널이 count라는 변수 값을 1 증가시킨다고 한다면, count++이라는 고급 언어는 CPU 내부에서는 여러 개의 인스트럭션을 통해 실행됩니다. 그래서 count++은 메모리에 있는 변수 값을 CPU안의 레지스터로 불러들이고, 레지스터 값을 1 증가시키고, 연산된 레지스터 값을 다시 메모리의 변수 위치에 저장하는 과정으로 나뉘게 됩니다.
그런데 만약 메모리에 있는 변수 값을 CPU안의 레지스터로 읽어들인 상태에서 인터럽트가 들어오면, 인터럽트 처리 루틴이 실행될 것이고 인터럽트 핸들러가 실행이 됩니다. 여기서 인터럽트 핸들러도 커널에 있는 코드기 때문에 커널에 있는 데이터인 count에 접근할 수가 있습니다. 그래서 여기서 만약 count를 -1을 빼고 인터럽트 처리가 끝나서 커널로 돌아오더라도, 인터럽트 전에 감소시키기 전의 메모리 변수를 이미 읽어들인 상태이므로 +1 증가한 것만 반영이 되는 문제가 생깁니다.
그래서 이러한 문제를 해결하기 위해서 중요한 변수 값을 건드리는 동안에는 인터럽트가 들어와도 인스트럭션이 완료될 때까지는 인터럽트 처리를 안하는 방법이 있습니다. 결론적으로 순서를 정해주면 되는 것입니다. 하지만 무작정 매번 막다보면 비효율적인 문제가 발생할 수 있습니다.
(2) process가 System call을 하여 kernel mode로 수행 중인테 context switch가 일어나는 경우
위에서 잠깐 언급했지만, 프로세스는 실행 시에 프로세스 자신의 코드뿐만 아니라 시스템 콜을 통해 운영 체제에게 서비스를 대신 요청하는 경우가 많이 있습니다. 그래서 프로그램은 유저 모드와 커널 모드를 번갈아가면서 실행하게 되는데 이때 CPU를 독점적으로 쓰는 것이 아닌 정해진 할당 시간이 있고, 할당 시간이 끝나면 CPU를 반납하게 됩니다.
그런데 만약 할당 시간이 끝난 시점이 본인의 코드를 실행하던 유저 레벨이 아닌, 커널의 코드를 실행 중 커널의 데이터를 변경하는 도중이었다고 가정하면 문제가 생깁니다.
위 그림을 예시로 설명드리겠습니다. 만약 A라는 프로세스가 커널 코드에서 count라는 데이터를 +1 증가시키던 도중에 할당 시간(Time quantum)이 끝나 CPU가 B라는 프로세스에게 넘어갑니다. B라는 프로세스는 작업 중 시스템 콜을 통해 커널에게 요청을 하고, 커널에서 count라는 변수를 또 +1 증가시키는 작업을 합니다. 이후 할당 시간이 지나 다시 프로세스 A에게 넘어왔지만, 프로세스 A는 이미 count 변수를 읽어들인 상태이기 때문에 프로세스 B에서 증가한 것은 반영이 되지가 않는 문제가 생깁니다.
일반적인 이런 문제의 해결 방법은 어떤 프로세스가 커널 모드에 있을 때는 할당 시간이 끝나도 CPU를 뺏기지 않게 하는 것입니다. 할당 시간이 정확하게 지켜지지는 않겠지만, Time sharing 방식에서는 시간에 조금 편차가 생겼다해서 그렇게 큰 문제가 생기는 시스템이 아니기 때문에, 오히려 이런 문제를 간단하게 해결하는 방법이 됩니다.
(3) Multiprocessor에서 shared memory 내의 kernel data
앞의 두 예시가 CPU가 하나만 있었다면, 지금의 예시는 CPU가 여러 개 있는 환경입니다. 이 예시에서는 앞서 설명한 방법처럼 인터럽트를 막아서는 해결이 되질 않습니다. 왜냐하면 CPU에서 데이터를 수정하는데 인터럽트를 막는다고 데이터를 못 읽어가는 것이 아니기 때문입니다. 이전에는 CPU가 하나라서 작업을 하던 도중 CPU 제어권이 넘어가는 문제였지만, 지금의 예시는 근본적으로 작업 주체가 여럿이라는 것입니다.
그래서 CPU가 여러 개 있는 환경에서는 lock을 걸어 어느 누구도 데이터에 접근 못하게 해야합니다. 즉 CPU가 메모리에서 데이터를 가져갈 때, 데이터에 락을 걸어서 누구도 데이터에 접근하지 못하게 해놓고 데이터를 변경하는 것입니다. 이후 변경된 데이터를 다시 저장하면 락을 풀고 다른 CPU가 그 데이터에 접근할 수 있게 하는 방식입니다.
4. 프로세스 동기화 문제
앞서 예시를 세 가지 들어서 설명드렸는데, 결국 프로세스 동기화 문제라는 것은,공유 데이터(shared data)의 동시 접근(concurrent access)이 데이터의 불일치 문제(inconsistency)를 발생시키는 것을 말합니다. 그래서 이 일관성(consistency) 유지를 위해서는 협력 프로세스간의 실행 순서를 정해주는 매커니즘이 필요합니다.
다음 포스팅에서는 구체적인 소프트웨어적인 해결 방법에 대해 소개드리겠습니다.
참고자료
[KOCW 이화여대 반효경 교수님 - Process Synchronization 1]
https://core.ewha.ac.kr/publicview/C0101020140401134252676046?vmode=f
[ Chapter5 Operating System Concepts - Abraham Silberschatz ]
https://www.yes24.com/Product/Goods/89496122