-
커널 동기화 ?
- 메모리를 공유하는 응용 프로그램은 항상 동시적인 접근으로부터 공유된 자원을 보호해야 한다.
- 다수의 실행중인 스레드가 동시에 데이터를 변경할 경우 다른 스레드가 변경한 부분을 또 다른 스레드가 잘못 덮어써버릴 가능성이 있다.
-
멀티프로세싱, 선점형 스케줄링 환경에서는 다양한 동시성 문제가 발생할 수 있다.
-
Critical Region(위험구역) and Race Condition (경쟁 상태)
- 위험구역이란 공유된 데이터를 접근하여 조작하는 코드 부분을 가리킨다. 원자적 실행을 보장해야 한다.
-
경쟁상태란 스레드들이 위험구역에 들어가기 위해 경쟁하는 상태.
-
락킹(Locking)
- 한번에 오직 하나의 스레드만이 공유하는 자료구조를 조작할 수 있다는 것을 확실할 방법.
- 특별한 구역에서 다른 스레드가 동작하고 있을 때 해당 자료구조를 접근하지 못하게 하는 방법.
-
락은 동시성을 방지하여 경쟁상태로부터 큐를 보호할 수 있다.
- 스레드는 방에 들어서면서 방문을 잠근다. 공유 데이터의 사용이 끝나면 스레드는 자물쇠를 열고 방을 떠난다.
- 만약 다른 스레드가 방문에 도착했을 때 문이 잠겨져 있다면, 안에 있는 스레드가 문을 열고 나올 때까지 기다린 후에 방에 들어가게 된다.
-
스레드는 락을 잠그고, 락은 데이터를 보호한다.
-
동시성
-
프로그램들이 선점되면서 스케줄링 된다는 사실에서 비롯된다. 어떤 프로세스가 위험지역에 있을 때 비자발적으로 선점돼 버리는 일이 발생할 수 있다.
- 유사동시성(peudo-concurrency) - 실제로는 동시에 발생하지 않지만 서로 엇갈려서 실행돼 마치 동시에 실행되는 것과 같은 효과가 발생.
- 진정한동시성(true-concurrency) - 대칭형 멀티프로세싱 시스템에서 두 프로세스는 정확히 가튼 시간에 하나의 위험지역에 진입 할 수 있다.
-
커널에서의 동시성의 원인
- 인터럽트 - 비동기적으로 어느때나 발생하여 현재 실행중인 코드를 중단시킨다.
- softirq와 태스크릿 - 커널은 현재 동작중인 코드를 중단하기 위해 거의 언제라도 softirq나 태스크릿을 레이즈하거나 스케줄할 수 있다.
- 커널 선점 - 커널도 선점형이므로, 커널에 있는 한 태스크가 다른 태스크를 선점할 수 있다.
- 유저공간에서의 휴면과 동기화 - 커널의 태스크는 휴면할 수 있으며 따라서 스케줄러가 새로운 프로세스를 실행하게 된다.
- 대칭형 멀티프로세싱 - 2개 이상의 프로세서가 코드를 동시에 실행할 수 있다.
-
동시성으로 인해 문제가 발생되는 경우 (락이 없다면..) : 경쟁상태가 발생
- 커널에서 어떤 자원을 조작하고 있는 도중에 인터럽트가 발생하여 같은 자원에 접근하는 경우.
- 커널이 공유 자원을 사용하고 있는 동안 커널 코드가 선점되는 경우.
- 위험지역을 실행하는 도중 커널 코드가 휴면하는 경우.
-
두 프로세서가 동시에 공유데이터에 접근하는 경우.
-
-
보호영역의 결정
-
동시에 접근될 수 있는 모든 코드는 보호가 필요로 하므로, 사실 보호가 필요없는 코드를 먼저 찾아내는 법도 있다.
- 특정스레드에 로컬한 데이터가 있을 경우.( 로컬자동변수, 스택에서만 존재하는 자료구조들.. )
- 특정 태스크에 의해서만 사용되는 데이터.
-
보호영역의 선정 ( 커널의 거의 모든 전역 데이터와 공유 데이터는 어떠한 형식으로든 동기화. )
- 데이터가 전역적인가 ? 다른 스레드가 이 데이터에 접근 가능한가?
- 데이터가 프로세스 컨텍스트와 인터럽트 컨텍스트간에 공유되는가?
- 데이터를 사용하는 도중 프로세스가 선점되는 경우, 새로 스케줄된 프로세스가 같은 데이터에 접근하는가?
- 현재 프로세스가 휴면(or 블록)하는 경우가 있는가? 만약 그렇다면 휴면(블록)시 공유 데이터가 어떤 상태에 놓이게 되는가?
- 다른 곳에서 이 데이터가 해제되지 않으려면 어떻게 해야 하는가?
-
이 함수가 다른 프로세서에서 호출되면 어떤 일이 벌어지는가?
-
-
데드락(Deadlock)
-
어떠한 스레드도 더 이상 진행할 수 없는 상태
- 각 스레드가 어떤 자원을 얻으려 대기하지만 이미 모든 자원의 락이 잡혀있을 때 발생한다. 모든 스레드가 서로에 대해 대기하므로 이미 잡고 있는 자원을 해제할 수도 없다.
- 셀프 데드락(self-deadlock) 이란 어떤 스레드가 자기 자신이 이미 잡고 있는 락을 다시 얻으려 시도할려고 할때 발생.
-
죽음의 포옹(deadly embrace) or ABBA 데드락 이란 2개의 스레와 2개의 락이 있는 경우 발생.
- 스레드1이 락 A를 얻음 / 스레드2가 락 B를 얻음
- 스레드1이 락 B를 얻으려 함 / 스레드2가 락 A를 얻으려 함
- 스레드1이 락 B에 대해 대기 / 스레드2가 락 A에 대해 대기
-
데드락 방지
-
중첩된 락은 반드시 같은 순서로 잠겨져야 한다. 죽음의 포옹을 방지.
- 서로 다른 구조체를 보호하는 cat, dog, fox 라는 3개의 락이 있을 때 어떤 함수가 cat->dog->fox 순서로 접근을 하였다.
- 다른 모든 함수 역시 같은 순서로 락들을 잠가야 한다.
-
기아현상(starvation)을 방지해야 한다. 코드가 종료하는가를 되짚어 봐야 한다. 어떠한 코드도 무한대기가 일어나서는 안된다.!
- 락이 풀리기를 대기중인 스레드들은 적당한!! 시간에 락을 얻을 수 있어야만 한다.
- 같은 락을 두 번 잠그지 않아야 한다.( 리눅스에서는 재귀적 락을 제공하지 하는다. )
-
락은 최대한 단순하게 설계해야 한다.
-
-
-
경쟁과 확장성
-
현재 사용되고 있는 어떤 락을 다른 스레드가 얻으려 하는 상황을 락경쟁(Lock Contention) 혹은 경쟁이라고 한다.
- 경쟁이 심한 락일수록 시스템 성능 저하에 더 큰 영향을 미친다.
- 확장성이란 어떤 시스템이 얼마나 잘 확장될 수 있는가를 가리킨다.
- 락킹의 세세함(granularity) 이란 그 락이 보호하는 데이터의 크기를 고려하는 것을 의미한다.
-
정확하지않은(coarse)락은 많은 양의 데이터, 전체 서브시스템의 자료구조를 보호하는 경우이다.
- 락경쟁이 심할 경우 확장성의 저하로 이어진다.
-
매우 촘촘한(fine grained)락은 매우 적은 양의 데이터, 큰 구조체에 속한 하나의 항목만을 보호한다.
- 충분한 락 경쟁이 없는 경우 소모적인 부하로서 작용한다.
-
이 글은 스프링노트에서 작성되었습니다.