[OS] Process Synchronization 1 : Race Condition

Doodung·2022년 5월 5일
0

OS - 운영체제

목록 보기
12/15
post-thumbnail

데이터의 접근


다음과 같은 방식으로 데이터가 저장된다.

연산 하는 부분 → execution box

저장하는 부분 → storage box

데이터를 읽기만 하면 문제가 될 게 없다. 그렇지만 결과를 다시 저장해야 하는 방식에서는 누가 먼저 읽어갔는지에 따라 결과가 달라질 수도 있다.
그럴 때 동기화 문제가 일어나고, 그것을 해결하는 방법에 대해 알아볼 것이다.

Race Condition


storage box를 혼자 사용한다 하면 문제가 되지 않지만, 여러 execution box가 공유한다고 생각하면 문제가 발생한다.
왼쪽은 1 증가 시킬려고 하는 것이고 오른쪽은 1 감소 시키려고 하는 것이다. +1 -1 하면 원래값이 되어야 한다.
그런데 왼쪽이 하나 증가시키는 동안에 오른쪽에도 진행됨 때문에 1을 빼는 결과만 저장이 된다. 이게 동기화 문제이다.

여러 주체가 하나의 데이터를 동시에 접근할려고 할 때, race condition (경쟁상태)에서 원치않는 결과를 얻을 수 있다. 이것을 조율해주는 방법이 필요하다.

프로세스가 연산의 주체고, 그 프로세스의 주소공간이 저장되어있는 위치이므로, 프로세스는 실행하면서 자기 주소공간에 있는 데이터를 읽어서 연산하고 다시 주소에 쓴다.

  • 멀티 프로세서 시스템에서 메모리를 공유하고 있다면 문제가 생길 수 있다.
    프로세스는 자기 자신만의 주소공간에 접근할 수 있지만, 공유메모리를 사용하는 프로세스에서 그 공유 메모리를 읽고있는데, 다른 프로세스가 또 그 공유 메모리를 읽어서 작업을 하게되면 문제가 생길 수도 있다.

  • 더 중요한 문제는 운영체제 커널과 관련하여 생기는 문제들이다.
    프로세스는 race condition이 발생할 문제가 없다. 프로세스가 운영체제에게 대신 요청해야 하면 시스템 콜을 하는데, 커널의 코드가 그 프로세스를 대신해서 실행하게 된다. 이때 커널의 데이터에 접근한다.
    다른 프로세스에게 cpu가 넘어갔는데 또 시스템콜을 해서 커널 코드가 실행이 되면 이러한 race contion 문제가 발생할 수 있다.

  • 커널 실행중인데 인터럽트가 들어올 수 있다. 지금 하던 일을 멈추고 인터럽트 코드 실행할텐데 이것도 커널코드이기 때문에 문제가 생긴다.
    유저레벨에서는 큰 문제가 안생기지만, 커널에 들어가다 보면 커널에 있는 데이터는 공유데이터이기 때문에 문제가 생길 수 있다.

OS에서 race condition은 언제 발생하는가?

  1. 커널 수행 중 인터럽트 발생 시
  2. 프로세스가 시스템콜을 하여 커널모드로 수행중인데 컨텍스트 스위치가 일어나는 경우
  3. 멀티프로세서에서 공유메모리 내의 커널 데이터

1. 커널 수행 중 인터럽트 발생 시의race condition

운영체제 커널이 cpu에서 실행하고 있음. 그러면서 count++를 하고 있었음. 보통 이런 고급언어로 된 문장은 cpu 내부에서는 여러개 인스트럭션을 통해 실행이 된다.

카운트라는 메모리 변수값을 1 증가시킨다는 것은 메모리에 있는 변수값을 cpu로 불러들이고, 1 증가시키고, 다시 메모리 변수 위치에 갖다 쓰고, 이런식으로 여러개 인스트럭션으로 나누어 실행이 된다.

문제는 이 변수를 cpu로 읽어들인 상태에서 인터럽트가 들어왔을 경우 이 것을 멈추고 인터럽트 처리루틴으로 넘어가게 된다.

인터럽트 핸들러도 사실 커널에 있는 코드이다. 인터럽트 핸들러가 처리되는 도중에 커널에 있는 데이터인 카운트 -1 하고 다시 원래 상태로 되돌아오게 된다.

메모리 변수를 cpu 변수까지 읽어오는건 했으니까 +1 하고 저장을 할텐데, 이 시점이 되면 원래 count는 원래 값이랑 똑같아야 하는데 -1 은 반영이 안되고, 결국 +1만 반영이 된다.

  • 그래서 이 문제를 해결하기 위해서 중요한 변수값을 건들이는 동안에는 인터럽트가 들어와도 인터럽트 처리 루틴으로 넘기는게 아니라 이 작업이 끝날때까지는 인터럽트를 disable 시키는 것이다. 그리고 작업 끝나면 인터럽트 처리 루틴으로 넘겨서 race contion에 문제가 발생하지 않게 한다.

결국에는 순서를 정해주면 된다.


2. 프로세스가 시스템콜을 하여 커널모드로 수행중인데 컨텍스트 스위치가 일어나는 경우의 race condition

어떤 프로세스가 실행이 된다는 것은 본인의 코드만 실행하는게 아니라 시스템콜을 통해 운영체제에게 서비스를 대신해달라고 요청하는 경우가 많이 있다.

그래서 프로그램은 유저모드와 커널모드를 번갈아가며 실행한다. 이때 cpu를 독점적으로 쓰는 것이 아니라 할당 시간이 있고, 할당 시간이 끝나면 cpu를 반납한다.

a가 cpu 쓰고있다가 cpu가 b한테 넘어감. b가 cpu쓰다가 다시 할당 끝나면 a한테 넘어감. 이 할당 시간이 끝난 시점이 본인의 코드(유저 레벨)를 실행하고 있다가 시스템 콜을 하면 k -> 커널 코드가 실행하는데, 만약 count 라는 값을 1 증가시키는 도중이었는데 할당된 시간이 끝난다면?

그래서 b한테 넘어감. k에서 count를 또 건드림. 그래서 총 2가 증가되어야 하는데 밑에서의 값인 1증가가 반영이 안됌.

  • 이런 문제는 어떻게 해결하냐면, 프로세스가 커널모드에 있을 때는 할당 시간이 끝나도 cpu를 뺏기지 않도록 하는 것이다.
    작업 도중에 cpu를 뺏는것이 아니라 할당시간이 끝나더라도 커널모드가 끝나는 그때 cpu를 빼앗음.
    할당 시간이 정확하게 지켜지진 않을것임. 그렇지만 어차피 time sharing은 realtime system이 아니라서 이런 문제를 쉽게 해결할 수 있다.

3. 멀티프로세서에서 공유메모리 내의 커널 데이터에서의 race condition

자주 등장하진 않음. 위의 방법으로 해결안된다. cpu에서 데이터를 읽어서 수정하고 있는데 다른 cpu가 데이터를 안읽을순 없으니까. 근본적으로 작업 주체가 여럿이 있기 떄문에 생기는 문제임.

그래서 이러한 cpu가 여럿이 있는 환경에서는 데이터를 접근할때 락을 걸어야 한다. 락을 걸어서 데이터에 접근 못하게 하고 데이터를 변경을 한다. 저장이끝나면 락을 풀어서 다른 cpu가 데이터를 접근할 수 있게.

이런 개별 데이터에 대해서 락을 걸고 풀 수 있고, 더 쉽게 만들려면 커널에 접근할 수 있는 cpu를 매순간 1개만 접근할 수 있게 하면.
—> 커널 전체를 하나의 락으로 막고 , 커널 빠져놔올때 커널 락을 푸는 방법으로. 대단히 비효율적이 된다 . 이 방법보단 각각의 데이터별로 락을 걸었다 푸는게 좋다.


Process Synchronization 문제


공유 데이터의 동시 접근은 데이터의 불일치 문제를 발생시킬 수 있다.

  • 일관성 유지를 위해서는 협력 프로세스간의 실행 순서를 정해주는 매커니즘이 필요하다

< Race Condition>

  • 여러 프로세스들이 동시에 공유 데이터를 접근하는 상황
  • 데이터의 최종 연산 결과는 마지막에 그 데이터를 다룬 프로세스에 따라 달라짐
  • race condition을 막기 위해서는 concurrent process는 동기화(synchronize) 되어야 한다.

Example of Race Condition

→ 보통은 문제가 생기지 않는다. 특별히 이 두 프로세스간에 공유데이터를 쓴다던지, 실행 도중 커널에 있는 데이터를 건드릴때 cpu가 넘어갈때던지, 이렇게 특별한 상황에서 문제가 된다. 단순히 프로세스가 1에서 2로 넘어간다해서 문제가 생기지 않는다.

profile
반가워요!

0개의 댓글