volatile 과 restict

Programming/C 2013. 2. 15. 02:40 |

volatile : 최적화를 수행하지 마세요.


volatile int num;

volatile int* ptr;

이렇게 변수 num을 volatile로 선언하면, 이는 컴파일러에게 다음과 같은 메시지를 전달하는 효과가 있다.

"변수 num에 저장된 값은 순간적으로 (일시적으로) 다른 영역으로부터 참조될 수 있습니다. 그러니 코드 최적화를 수행하면 안되요"


num+=10;

num+=20;

num+=30;

이와 같은 코드가 있다고 가정할 때 컴파일러는 변수 num에 한번에 60을 넣는다. 

이런 식으로 변함.

num+=60;


이는 컴파일러의 코드 최적화(code optimization) 기능에 따른 것이다.


하지만, 이런 코드 최적화가 문제가 되는 상황이 존재한다. 다른 영역의 프로그램 또는 하드웨어를 통해서 변수 num에 저장된 값이 참조되는 경우이다.

즉, 변수 num에 저장된 값이 10 증가되고 나서 20이 증가되기 이전에 순간적으로 다른 영역으로부터 값이 참조될 수 있다.  이러한 경우에는 코드 최적화가 치명적인 문제가 된다. 

그래서 volatile 을 써서 변수 num과 관련해서는 코드 최적화를 수행하면 안된다고 컴파일러에게 알려주어야 한다.

volatile int num = 20; 이런식으로 선언하면 된다.


※ 참고로 이렇게 volatile로 선언된 변수 값의 변경은 항상 메인 메모리(RAM)에 반영이 된다. volatile 선언이 없는 변수는 성능의 향상을 위해서 값의 변경이 캐쉬 메모리(또는 레지스터)에만 반영되었다가, 뒤늦게 메인 메모리에 반영되기도 한다.

그리고 volatile로 선언된 변수의 값은 참조될 때에도 캐쉬가 아닌 메인 메모리로부터 참조가 이뤄진다.


정리하면 volatile로 선언된 변수는 캐쉬 메모리를 거치지 않는다. 다른 영역으로부터 언제 어떠한 형태로 값의 참조가 이뤄질지 모르기 때문에 값의 변경이 실시간으로 메인 메모리에 반영이 된다.



○ 포인터 변수 선언에서의 volatile 선언


: 포인터가 다른 영역에서  참조될 수 있음을 의미하는 것이 아니라, 포인터가 가리키는 메모리 공간이 다른 영역으로부터 참조될 수 있음을 의미하는 것이다. 따라서 volatile로 선언된 포인터 변수의 *연산은 코드 최적화의 대상에서 제외가 된다. 




restrict : 원하는 대로 마음껏 최적화를 수행.


restrict는 volatile과 반대의 의미를 지니고 있다. volatile이 코드 최적화에 제한을 거는 선언이라면, restirct는 코드 최적화를 유도하는 선언이다. 그리고 restirct 선언은 포인터에만 선언할 수 있다.

int* restirct ptr;

이 포인터가 가리키는 메모리 공간은 이 포인터만으로 접근이 가능한 영역이다 라고 컴파일러에게 알려준다.


int main(void)

{

      int num = 10;

      int* ptr = #

}

이 때 포인터 ptr을 restrict로 선언하는 것은 적절치 않다. 왜냐하면 포인터 ptr을 이용해서 접근 가능한 메모리 공간은 num이라는 변수 이름으로도 접근이 가능하기 때문이다. 


int main(void)

{

      int* restirct ptr = (int*)malloc(sizeof(int));

}

위와 같이 선언된 포인터 ptr은 restrict로 선언하기에 적절하다. 왜냐하면 malloc 함수를 통해서 할당된 메모리 공간은 포인터 ptr을 통해서만 접근이 가능하기 때문이다.


이렇게 포인터가 restrct로 선언되면, 해당 포인터가 가리키는 메모리 영역의 접근 연산은 캐쉬 메모리를 기반으로 최고의 성능을 낼 수 있도록 코드가 최적화된다.


Posted by scii
: