반응형

0.🚶들어가며

프로세스 동기화에 대한 내용을 다뤄보려 합니다. 첫 번째 주제로는 동기화가 무엇인지, 동기화가 왜 필요한지, 관련 개념은 어떤 것이 있는지에 대해 소개해보도록 하겠습니다. 


1.❓동기화란 무엇인가❓

 동기화 필요성에 대한 이해를 돕기 위해 한 예시를 들어보겠습니다. 

동시에 실행되고 있는 두 코드가 있다고 가정해봅시다. 언뜻 보면 전혀 문제가 없어 보이는 코드입니다. 하지만 다음과 같은 순서대로 실행된다면 문제가 발생합니다.

  • 좌측 코드 라인1 > 우측 코드 라인1 > 우측 코드 라인2 > 좌측 코드 라인2

(물약 먹는 코드 + 공격받는 코드)를 실행시켰을 시, health의 최종 값은 기존보다 40(50 - 10) 증가되어있음을 기대하는데 위와 같은 순서대로 실행된다면 health는 50이 증가되어있게 됩니다. 이와 같은 상황이 왜 일어났는지 좀 더 알아봅시다.

 

컴퓨터는 연산을 할 때(ex : x =  x + 1)  데이터를 1️⃣읽어와서 2️⃣연산을 하고 3️⃣저장하는 과정을 거칩니다. 즉 이 세 단계가 atomic 하지 않습니다. 이러한 이유 때문에 위와 같은 문제가 발생한 것이죠.

 

즉, 여러 프로세스들이 동시에 공유 데이터를 접근하는 상황에서는 데이터의 최종 연산 결과가 마지막에 그 데이터를 다룬 프로세스가 무엇이었냐에 따라 달라지게 됩니다. 개발하는 입장에서 예상하는 결과를 얻기가 어려워지는 것이죠. 또한 위와 같이 공유 데이터에 여러 프로세스들이 접근하려 하고 이 때문에 결과 값에 영향이 가는 상태를 Race Condition이라고 합니다.

 

Race Condition으로 인해 Data Inconsistency가 발생한 것이고 Data Consistency를 유지하기 위한 메커니즘을 바로 동기화라고 합니다.


2.🏃Race Condition (경쟁 조건)

싱글 프로세서의 경우 크게 두 가지 경우에서 Race Condition이 발생합니다. 

1) OS에서 Race Condition이 발생하는 경우

기본적으로 프로세스는 독자적인 메모리 공간을 가지고 있기 때문에 프로세스 내부의 데이터에 여러 프로세스가 같이 데이터에 접근한다라는 개념이 성립하기 어렵습니다. 하지만 프로세스 A, B 두 개가 커널의 데이터를 조작하는 경우를 생각해보면 Race Condition이 발생할 수 있습니다. 

 

커널의 데이터를 여러 주체가 동시에 조작하려는 경우에 대해 보면

   

   1. Kernal mode에서 작업 수행 중 인터럽트 발생하는 경우

   2. Process가 System call을 하여 Kernel mode로 수행 중인데 Context switch가 발생하는 경우

 

두 가지 경우에서 Race Condition이 발생할 수 있습니다. 두 가지 경우에서 모두 atomic 하게 해야 할 연산을 다 수행하지 못하고 CPU 자원을 뺏기는 경우라 앞선 게임 코드 예시에서 본 것과 같은 문제가 생길 가능성이 존재하게 됩니다.

 

1번의 경우 Kernal mode 작업 도중 인터럽트가 발생하면 하던 작업을 멈추고 인터럽트 처리 루틴에 들어가게 되는데 이때 처리 루틴이 이전 Kernal mode 작업에서 사용하던 데이터를 가지고 하는 무언가를 하게 된다면 Race Condition이 발생합니다. 이를 막기 위해서는 해당 공유 자원에 대해서는 작업 시작 시 disable interrupt를 해야 합니다.

 

2번의 경우 Kernal mode 작업에서는 CPU를 빼앗기지 않도록 처리한다면 자연스럽게 해결되는 문제입니다.

2) Process 간 공유 메모리에서 Race Condition이 발생하는 경우

위에서 설명했듯 프로세스는 기본적으로 독자적인 메모리 공간을 가지고 있기에 서로 Race Condition이 발생하지 않는 게 일반적입니다. 하지만 Process 간 통신을 위해 공유 메모리를 설정하는 경우에는 프로세스 간에 Race Condition이 발생할 수 있습니다.

프로세스간 공유 메모리에서의 Race Condition

이런 상황에서 일관성 유지를 위해 협력하는 프로세스 간의 실행 순서를 정해주는 메커니즘이 필요하게 됩니다. 


3.🧱Critical Section (임계 영역)

위에서 설명했던 Race Condition과 항상 같이 나오는 개념이 Critical Section입니다. Critical Section은 공유 데이터에 접근하는 코드 부분입니다. 이 부분에 대한 처리를 잘해주어야 위에서 설명했던 동기화 이슈를 잘 해결할 수 있는 것이죠.

 

Critical Section에서 발생할 수 있는 문제를 해결하기 위해서는 다음 세 가지 조건을 만족해야 합니다.

1) 상호 배제 (Mutual Exclusion)

  • 한 프로세스가 Critical Section에서 작업 중이라면 다른 프로세스는 Critical Section에 들어가면 안 된다.

2) 진행 (Progress)

  • 아무도 Critical Section에 있지 않은 상태에서 Critical Section에 들어가고자 하는 프로세스가 있다면 들어가게 해주어야 한다.

3) 유한 대기 (Bounded Wating)

  • 프로세스가 Critical Section에 들어가려고 요청한 후부터는 무한정 대기해서는 안된다. 즉 프로세스 A, B, C가 있을 때 A와 B만 계속 임계 영역에 들어가서는 안된다.

위 조건에 대해 아직은 감이 잘 안 오실 수 있을 것 같습니다. 다음 글에서는 위 조건들을 왜 만족시키지 않으면 어떤 점이 문제인지, 각 조건을 만족시키기 위해 어떤 방법을 사용하는지에 대해 알아볼 것입니다. 우선은 이런 것이 있구나 하며 다음 글로 가봅시다!


4.💨나가며

다음 글에서는 임계 구역을 다루기 위해 어떤 방법들을 사용하는지에 대해 알아보겠습니다.

 

 

복사했습니다!