Critical section 문제를 해결하는 하드웨어 지원 (Hardware Support for Synchronization)

이찬영·2021년 8월 17일
0

OS

목록 보기
11/35

하드웨어 기반 해결책

소프트웨어 기반 해결책의 문제점

peterson 해결 방법과 같은 소프트웨어 기반 해결책은 최신 컴퓨터 아키텍처에서 명령어 순서 재정렬로 인한 문제가 발생할 수 있다. 그렇기 때문에 하드웨어는 특수한 명령어를 통해 해결책을 지원한다.

Memory Barriers (메모리 장벽)

컴퓨터 아키텍처가 응용 프로그램에게 제공하는 메모리 접근 시 보장되는 사항을 결정하는 방식을 Memory Model이라고 한다.

강한 순서

한 프로세서의 메모리 변경 결과가 다른 모든 프로세서에 즉시 보임

약한 순서

한 프로세서의 메모리 변경 결과가 다른 모든 프로세서에 즉시 보이지 않음

메모리 모델에 따른 문제점

메모리 모델에 따라서 메모리 변경 결과를 확신 할 수 없다. 이러한 문제를 해결하기 위해 Memory Barriers (메모리 장벽) 또는 Memory fences(메모리 펜스)를 사용할 수 있다.

예제

아래 예제는 flag값이 x값 보다 먼저 적재 되도록 보장한다.

while(!flag)
	memory_barrier();    
print x;

아래 예제는 x값이 flag값 보다 먼저 적재 되도록 보장한다.

x=100;
memory_barrier();
flag=true;

Hardware Instructions (하드웨어 명령어)

아래 소개하는 두 하드웨어 명령어는 원자적(atomcially)으로 실행된다. 명령어가 원자적으로 실행된다는것은 두 명령어가 동시에 실행되어도 스케쥴링에 의해 쪼개지지 않고 항상 순서대로 실행된다는 의미이다. 명령어가 실행되면 해당 명령이 끝날때까지 현재 명령어만 실행됨을 보장한다.

test_and_set() 정의

boolean test_and_set(boolean *target){
	boolean rv = *target;
    *target = true;
    
    return rv;
}

test_and_set()을 사용한 mutual exclusion(상호배제) 구현

do{
	while(test_and_set(&lock));
    
	/* critical section */
    
	lock = false;
    
	/* remainder section */
    
}while(true);

compare_and_swap() 정의

int compare_and_swap(int *value, int expected, int new_value){
	int temp = *value;
    
	if (*value == expected)
		*vaule = new_value;

	return temp;
}

compare_and_swap()을 사용한 mutual exclusion(상호 배제) 구현

while(true){
	while(compare_and_swap(&lock, 0, 1) != 0);
    
	/* critical seciton */
    
	lock = 0;
    
	/* remainder section */
}

compare_and_swap()을 사용한 한정된 대기 조건을 만족시키는 상호 배제

while (true) {
        waiting[i] = true;
        key = 1;
        
        while (waiting[i] && key == 1)
            key = compare_and_swap(&lock, 0, 1);

        waiting[i] = false;

        /* critical section */

        j = (i + 1) % n;
        while ((j != i) && !waiting[j])
            j = (j + 1) % n;

        if (j == i)
            lock = 0;
        else
            waiting[j] = false;
        
        /* remainder section */
    }

Atomic Varialbes(원자적 변수)

위에서 설명한 compare_and_swap()는 상호 배제를 제공하기 위해 직접 사용되지 않는다. 오히려 critical section의 문제를 해결하는 다른 도구를 구축하는데 기본 구성 요소로 사용된다. 그렇게 구현된 도구는 Atomic Variables(원자적 변수)로 해당 자료형에 대한 원자적 연산을 제공한다.

예 - 원자적 정수를 증가시키는 함수 incremental()

void increment(atomic_int *v){
	int temp;
    
	do{
	    temp = *v;
	}while(temp != compare_and_swap(v, temp, temp+1));
}

문제점

원자적 연산을 지원하기 때문에 상호 배제는 보장할 수 있다. 하지만 모든 상황에서 race condition을 해결할 수 는 없다.

예를 들기위해 이 글에서 설명한 생산자-소비자 패턴의 코드를 보겠다.
우리는 count 변수를 원자적 정수로 정의를 할 수 있다. 하지만 소비자가 여러 프로세스라면 소비자에서 count 값이 바뀌자마자 count != 0이 되어 while문을 탈출하고 데이터를 소비하게 된다. 우리는 한 소비자가 하나의 데이터를 소비 하도록 생각하지만 실제로는 한 데이터를 두 소비자가 소비하고 있는 문제가 발생할 수 있다.

0개의 댓글