LISTORY
[윈도우즈 시스템 프로그래밍] 유저 모드 동기화 본문
뇌를 자극하는 윈도우즈 시스템 프로그래밍 책 관련 유투브 강의 정리이다.
이번 시간에 다룰 내용은 유저모드의 동기화 부분이다.
YouTube 주소 : 유저 모드 동기화
유저 모드의 동기화
동기화 기법은 우리에게 단순히 제공이 되는 기능이다.
API 상으로 동기화 기법은 추상적으로 밖에 보이지 않는다.
어떻게 동기화가 이루어 지는지 실질적으로 보기 위해선 하드웨어적 지식이 필요하다.
하지만 동기화의 경우, 어떻게 이루어지는 아는 것보다, 사용을 하되 적절한 사용을 고려하는 것이 훨씬 더 중요하다.
메모리에 대한 모든 동기화 기법은 key를 생각하면 된다.
둘 이상의 쓰레드가 동시에 접근하는 것을 막기 위해선 열쇠를 가지고 접근을 허용한다고 생각하면 된다.
예제 코드를 보겠다.
CRITICAL_SECTION gCriticalSection; // key
InitializeCriticalSection(&gCriticalSection); // 초기화 ( 임계영역 접근에 관련된 모든 것을 스탠바이.. 즉, 최소한의 기본작업 요청)
......
/*
크리티컬의 섹션 요구
임계 영역의 시작과 끝을 정의하고,
시작에서 EnterCriticalSection()으로 열쇠 전달하며 호출한다.
임계영역의 끝에서 역시 LeaveCriticalSection()으로 열쇠를 인자로 전달한다.
*/
// 임계영역 진입을 위해 크리티컬 섹선 오브젝트 획득. 즉, 열쇠 획득
EnterCriticalSection(&CriticalSection);
임 계 영 역
// 크리티컬 섹션 오브젝트 반환. 즉, 열쇠 반환
LeaveCriticalSection(&CriticalSection);
......
DeleteCriticalSection(&CriticalSection);
기억해야 할 것은 크리티컬 섹션 키, 초기화, 획득과 반환이다.
여기서 임계 영역을 좁게 잡아버릴 필요 없이 처음부터 끝까지 잡아도 되지 않냐는 의문이 들 수 있다.
실제로 임계 영역은 넓게 잡으면 안정적이다.
하지만 성능상의 문제가 있다.
예를 들어, A B 쓰레드가 존재한다고 해보자. 임계 영역을 무척 넓게 잡았다.
A가 B보다 임계영역에 도착한 시간이 빨랐다면 A 스레드가 LeaveCriticalSection()을 할 때까지 B는 대기를 한다.
대기는 문제가 안된다. 하지만 필요없는 부분까지 임계영역으로 잡은 경우,
B 쓰레드가 기다리는 시간이 걸리는 부분은 너무 비효율적이다.
그러므로 임계영역 구성시, 최소한의 부분으로 필요한 부분만 감싸라 (정적으로)
⊙ 인터락 함수 기반의 동기화
사실, 우리가 임계영역으로 쓰는 부분은 변수 하나 두개일 경우가 많은데, 위의 방법은 지나치게 복잡한 감이 있다.
그런 경우를 위해 인터락 함수가 등장했다.
인터락 함수는 원자적 접근(Atomic Access)을 보장한다.
Atomic Access : 한순간에 하나에 의해서만 연산된다.
즉, 이 함수는 한순간에 하나의 쓰레드에 의해서만 호출이 완료되도록 허용된다.
InterlockedIncrement()는 값을 증가시키는 함수인데,
어떠한 쓰레드던간에 InterlockedIncrement()를 호출하면, 이 연산은 결코 둘 이상의 쓰레드에 의해 동시에 진행되지 않도록 보장해준다.
즉, 우리가 어렵게 동기화 부분을 설계하지 않아도 이 함수를 통해 증가하면 알아서 동기화가 되며 기능을 수행한다.
이렇게 임계 영역이 단순하다면 인터락 함수를 사용하는 것도 고려해보는 것도 좋다.
⊙ 커널 모드 동기화
다음 강의에서 자세히 다루므로, 여기선 간단히만 다루도록 하겠다.
A, B 쓰레드 존재한다. 이 두 쓰레드는 동시에 하나의 메모리에 접근한다.
여기서 A만 실행되야 할 경우, 가장 무식한 방법은 무엇일까?
스케줄러가 동작을 하지 못하도록 막아버리면 된다.
스케줄러가 동작 안하면 컨텍스트 스위칭 또한 하지 않으므로 B 쓰레드가 동작할 수 없다.
그럼 A 쓰레드는 스케줄러를 어떻게 정지시킬 수 있을까?
가장 무식한 방법으로 인터럽트를 Disable 시키는 것이 있다.
자세히 설명해보겠다.
타이머 인터럽트라는 것이 있다. 모두 아다시피 CPU는 클럭을 기준으로 일을 한다.
이 클럭이 상위로 올라올 때, OS에게는 타이머라는 인터럽트로 동작하게 된다.
하드웨어는 어떠한 현상을 OS에게 알릴 때 인터럽트로 알리고, 이걸 타이머 인터럽트가 발생했다 한다.
OS는 시간이 흘러가는 것을 이 타이머 인터럽트를 통해 알게된다.
스케줄러는 쓰레드들간의 실행을 시켜줄 때, 시간을 재야하므로 타이머 인터럽트가 필요하다.
즉, 하드웨어는 운영체제에게 인터럽트를 통해 시간을 알려는데, 이것을 DISABLE 시킨다면 OS가 시간이 흘러가지 않는 줄로 안다.
스케줄러는 시간이 흘러야 컨텍스트 스위칭을 하는데 시간이 흘러가지 않으므로 동작하지 않는다.
그러므로 A 쓰레드는 혼자 동작할 수 있고, 동작이 끝났을 경우 타이머 인터럽트를 다시 ENABLE 하도록 변경하면 된다.
'IT > 윈도우 프로그래밍' 카테고리의 다른 글
[윈도우즈 시스템 프로그래밍] 커널 모드 동기화(2) (0) | 2018.09.16 |
---|---|
[윈도우즈 시스템 프로그래밍] 커널 모드 동기화(1) (0) | 2018.09.16 |
[윈도우즈 시스템 프로그래밍] 쓰레드 동기화 기법1 (0) | 2018.09.03 |
[윈도우즈 시스템 프로그래밍] 2부 정리 (4) (0) | 2018.09.02 |
[윈도우즈 시스템 프로그래밍] 2부 정리 (3) (0) | 2018.09.01 |