본문 바로가기
CS/컴퓨터 구조

[Chapter 2.6 컴퓨터 구조 및 설계] 동기화와 동기화에 사용되는 하드웨어 명령어

by 베어 그릴스 2022. 7. 10.
320x100
본 정리는 CS422-컴퓨터 구조 및 설계 : 하드웨어/소프트웨어 인터페이스. David A. Patterson,존 헤네시 책을 바탕으로 하고 있음을 미리 알립니다.

 

병렬성과 명령어 : 동기화


태스크가 서로 독립적일 때에는 병렬처리가 쉽지만, 태스크가 서로 자원을 공유하는 경우가 많다.

 

예를 들어, 두 프로세서가 같은 메모리구역을 공유하고 있을 때, P1 프로세서가 데이터를 읽어오고 P2 프로세서가 데이터를 쓴다고 가정하면, P1 프로세서와 P2 프로세서의 순서에 따라 결과 값이 달라질 것이다.

 

이렇게 결과값이 달라지는 현상을 바로 데이터 경쟁관계(data races)라고 한다.

 

이러한 데이터 경쟁관계를 극복하기 위해선 하드웨어의 도움이 필수적이다.

 

컴퓨팅에 있어서 동기화 매커니즘은 일반적으로는 사용자 수준 소프트웨어 루틴에서 제공되는데 이 소프트웨어 루틴들은 하드웨어가 제공하는 동기화 명령을 사용하고 있다. 이러한 명령을 사용하여 단 하나의 프로세서만이 작업할 수 있는 영역을 생성할 수 있으며 이를 상호배제(mutual extension)이라 한다. 이렇게 생성된 동기화를 기본 동기화 프리미티브라고 한다. ex) lock unlock

 

왜 그러면 하드웨어가 제공하는 명령어를 사용해야만하는 것일까?

 

기본 동기화 프리미티브 조차 원소적으로 이루어져야하기 때문이다. 즉, lock unlock 등의 명령어가 실행될 때 자체에도 다른 프로세서가 끼어들면 안되기 때문에 하드웨어에서 이를 제공한다. 

 

이를 하드웨어 프리미티브라고 한다.

 

만약 하드웨어 프리미티브가 없다면, 기본 동기화 프리미티브 구현 비용이 매우 비싸질 것이다.

 

 

하드웨어 프리미티브


그러면 기본 동기화 프리미티브에 사용되는 하드웨어 프리미티브부터 한번 알아보자.

 

동기화 연산 구축을 위한 전형적인 연산은 원자적 교환(Atomic exchange)인데, 이 연산은 레지스터의 값을 메모리 값과 교환하는 것이다.

MIPS는 이를 위해 SWP명령어를 갖고 있다.

 

기본 동기화 프리미티브 (lock unlock)


 

이제 하드웨어 프리미티브가 기본 동기화 프리미티브를 만들기 위해 간단한 lock을 만들어보자.

 

lock은 0이면 사용 가능하고 1이면 불가로 표시한다고 가정한다.

 

접근하는 프로세서는 나만이 이 구역에 접근하여야 하니 l레지스터에 있는 값 1과 메모리에 있는 lock을 맞바꾸어 lock을 1로 만들어 이미 사용중이니 사용불가하다고 표시하려할 것이다.

 

만약, 맞바꾼 값이 0이면, lock 값이 1로 바뀌어서 다른 프로세서가 접근하지 못하게 될 것이다.

 

여기서 요점은 맞바꾸는 과정이 원소적으로 일어나서, 즉,  하드웨어 프리미티브로 일어나서 예측하지 못한 값을 읽어갈 일이 없다는 것이다.

 

 

ll(load link), sc(store conditional) 특수 명령어를 통한 swap 구현


MIPS에서는 동기화를 위해 두가지 특수명령어 쌍을 사용하는데,

바로 ll(load link)와 sc(store conditonal)이다.

 

ll rt, offset(rs)
sc rt, offset(rs)

 

 

우선 load link 명령어가 rs 주소의 값을 rt에 가져오고 이후에 sc가 실행되는데, 만약 load link 명령어에 의해 명시된 메모리 주소의 내용이 같은 주소에 대한 store conditonal 명령어가 실행되기 전에 바뀐다면 이 명령은 실패하고 rt에 0을 반환하고, 바뀌지 않았다면 주소에 rt값을 넣은 후 rt에 1을 반환한다.

 

즉, ll과 sc 사이에 rs 주소의 값에 대한 다른 프로세서의 접근이 없었다면 rs 주소의 메모리에 있던 값이 ll의 rt에 옮겨지고, sc의 rt에 있던 값이 rs 메모리 주소에 가고, sc의 rt에는 원소적으로 실행되었는지 실패했는지 정보가 0과 1로 나타나게 되는것이다.

 

$s4에 있는 값을 $s1의 주소에 넣고 $s1에 있던 값을 $s4에 다시 넣는다는 swap상황을 가정해보자.

위에서 봤던 SWP 명령어를 사용한것과 같은 효과를 내려면 ll과 sc를 사용하여야한다.

 

try: add $t0, $zero, $s4 #$t0=$s4 (exchange value)
	ll $t1, 0($s1) #load memory value to $t1
	sc $t0, 0($s1) #try to store exchange
		#value to memory, if fail
		#$t0 will be 0
	beq $t0, $zero, try #try again if store fails
	add $s4, $zero, $t1 #load value in $s4

천천히 순서대로 보면,

 

$t0에 바꾸고 싶었던 $s4 값을 복사해두고, ll과 sc를 통해 $s1의 주소에 있는 값을 $t1에 빼오고 $t0에 있던 $s4값을 $s1의 주소에 저장해준다. 이때 이것이 실패했다면 $t0엔 0이 담겨있을 것이고 그렇다면 try부터 다시 실행되게 될것이다.

만약 성공해서 1이 담겨있다면, $s4에 $s1에 있던 값이었던 $t1을 넣어준다.

 

이렇게 코드를 만듬으로써 원소적 swap을 구현할 수 있다.

 

 

 

 

728x90