Volatile in C/C++ #2

Tags:

Do you volatile? should you?

trax님 블로그에 인용안되었으면 그냥 넘어갔겠지만, trax님까지 잘못된 내용을 알고 계신 듯하여 다시 글을 씁니다.

const와 같이 따라다니는 변수형인 volatile은 실제로 문제에 접해보기 전엔 사용에 대한 필요성을 못느끼는 변수형입니다. const는 초기화 이후에는 데이타 의 변형이 불가능하게 됩니다. 반대적인 개념이 volatile이란 변수형입니다.

보통 PC에서 단일 task, process, thread (통칭 process라 하겠슴)에서는 사용할 필요를 느끼지 못하는 변수형입니다. 자 그럼 셋탑에서의 단일 process에 인터럽트 루틴이 있는 경우, 또는 multi-process인데 공용 메모리 (쉽게 전역변수)를 사용하는 경우에 그 변수를 volatile로 선언해두지 않으면 곤란한 경우를 당하게 됩니다. 로직엔 아무런 이상이 없는데 버그가 나오게 되죠.

인터럽트 루틴이 있는 단일 process의 경우를 먼저 예로 들면, is_lock이란 전역변수가 있습니다. 메인 루틴에서 변수를 셋팅하고 다음 코드를 수행하려 할때 인터럽트루틴이 호출되어 is_lock이란 변수를 바꾸어 놓습니다. 인터럽트 루틴이 끝나고 메인 루틴의 다음 코드로 넘어가게 되서 if (is_lock)이라고 해봅시다. 이때 인터럽트 루틴에서 바꾸어 놓은 결과가 반영되지 않는 경우가 발생합니다. 이런 경우 대부분 CPU에서 캐쉬를 사용 하는 경우이죠. 이때 이 변수를 volatile로 선언해 놓으면 변수를 참조할때마다 메모리에서 다시 reload하게 됩니다. 이해가 되셨는지…

multi-process에 공용메모리를 사용하는 경우도 위와 동일한 이유로 사용합니다.

(명사형 전성어미 ‘ㅁ’을 써서 ‘하겠음’이라고 써야하는 것을 ‘하겠슴’으로 쓴 부분을 제외하고라도) 이 설명은 완전히 잘못되었습니다. 먼저 이글을 읽어보시고, 다음 Scott Myers의 글을 읽어보세요.

comp.programming.threads의 글 역시 도움이 될 것입니다.

C나 C++ 자체에는 쓰레딩의 개념이 없습니다. 먼저 C의 경우.

The C language defines a series of “sequence points” in the “abstract
language model” at which variable values must be consistent with language
rules.

C++의 경우.

> The C++ standard does not deal with multiple threads of
> execution. So, the answer is “it depends on your threading
> environment”.

쓰레딩과 언어가 합체한 것은 자바나 C# 같은 언어의 경우일 뿐입니다. (C++의 경우엔 스트라우스트롭 아저씨가 그렇게 원하는 모든걸 다하는 general 한 언어를 위한 선택이죠. C++은 모든 문제를 풀 수 있게 할 뿐, 직접 문제를 풀지는 않는다는 거죠. 그래서 쓰레드는 C++의 일부가 아닙니다.)

volatile은 sequence points와만 상관이 있는데, 하필이면 그 sequence points는 가상의 단일 쓰레드를 가진 프로세서를 전제합니다. 따라서 멀티쓰레드 동기화와 상관이 없습니다.

volatile은 하드웨어와 연관될때나 의미가 있습니다. 쓰레딩의 해결에 쓰시면 안됩니다. volatile은 기껐해야 컴파일러 최적화만 막을 뿐 입니다. MMU의 동작은 메모리 베리어를 통해 해결해야하며 메모리 베리어의 삽입을 가장 간단히 하는 것은 synchronization construct 뿐입니다. 오죽하면 volatile을 갖고 comp.programming.threads에서 brain-dead 라고 하겠어요. 혹시 갖고 계신 책, 보고 있는 article에서 volatile은 멀티 쓰레딩을 위한 것이라고 나와있다면, 그 책/article이 잘못된 것입니다.

혹시라도 제 설명이 잘못되었다고 여겨지신다면 comp.programming.threads에 포스팅하고 주소를 알려주시면 감사하겠습니다.

Comments

3 responses to “Volatile in C/C++ #2”

  1. trax Avatar

    음… 잘못 아신 듯. 해당 글은 참고용으로 링크한 것인데, 그 전에 제가 단 3줄의 코멘트는 그게 아니라는 요지였는데… 제대로 이해하는 분이 아마도 없을듯… ^^

    OS 커널에서 동기화가 필요한 타입에 대해 단순히 volatile int를 사용하는 것이 아니라 구조체로 래핑해서 사용하고 있고, 다중 CPU에 대한 lock과 release를 위해 다른 방법을 사용하고 있음.

    커널에서는 단일 CPU에 대한 lock과 release가 구별되어 있고, 다중 CPU에 대한 lock과 release가 구별되어 있어요.

    이런 문제를 단순히 volatile 이라는 것으로 해결할 수 있고, volatile이 해결하는 것은 단일 CPU까지라는 것.

    trax, 약간 다른 부분도 있음. JVM하고도 다른 부분 있음.

    CPU에서 lock하고, volatile 접근, release 가능.

    여러 CPU에 대한 전역 lock 가능.

    아마, 이 세줄의 코멘트가 암호같아서 인 듯. JVM에서 얘기하는 부분하고 다르다는 것.

    CPU에서 lock, release가 가능한 것은 OS 커널 레벨에서 하는 얘기.(요즘 동기화는 커널에서만 다루고 있음. 실은 거의 다루지는 않지만… )

    volatile에 대한 시작은 민구씨와 저의 Singleton 패턴에 대한 것이 시작이었던 듯.

    http://network.hanbitbook.co.kr/view.php?bi_id=595

    아니면 할 수 없고. 요즘은 듀얼 코어(not CPU)의 시대라서 스레드에 대해서는 좀 더 확실하게 테스트하고

    장난할 수 있는 시대가 된 듯. ^^

  2. trax Avatar

    이런 문제를 단순히 volatile 이라는 것으로 해결할 수 있고, volatile이 해결하는 것은 단일 CPU까지라는 것.

    켁… 졸면서 쓴 듯… 이게 또 무슨 소리야.. ㅡ.ㅡ

    이 소리도 아닙니다… lock 이라는 건 CPU에서 제공하는 기능을 이용하는 것이고,

    volatile은 보조적인 수단.

    MMU의 memory reordering도 마찬가지로 mb(), rmb(), wmb() 등으로 직접 제어를 하고 있고,

    atomic operation이 필요한 곳은 down(), up() 등으로 모두 제어하고 있는데,

    이 부분들은 CPU를 직접 제어하는 부분이고, volatile은 보조적인 형태에 불과함.

    그리고, 라이브러리에서 제공하는 스레드 기능은 운영체제의 이런 기능들을 이용하는 형태에

    불과함.

  3. MKSeo Avatar
    MKSeo

    음 네.. 커멘트 고마와요. ㅎㅎ
    요즘은 정말 그때에 비하면 시대가 많이 바꼈어요..

Leave a Reply

Your email address will not be published. Required fields are marked *