volatile 키워드가 이해가 잘 안되네요

iankcpp의 이미지

volatile 설명 찾아보다가 읽게된 포스팅인데 잘 이해가 안되네요..

"임베디드 시스템 프로그래밍에서 volatile 키워드의 필요성
- 임베디드 시스템 프로그래밍 같은 경우 프로세서의 레지스터를 직접 제어하는 경우가 많다. 이 경우 만약 컴파일러가 주소가 같다는 이유만으로 중복되는 쓰기 명령을 없애버리면 하드웨어가 오작동 할 수 있다.

*(unsigned int *)0x8C0F = 0x8001;
*(unsigned int *)0x8C0F = 0x8002;
*(unsigned int *)0x8C0F = 0x8003;
*(unsigned int *)0x8C0F = 0x8004;
*(unsigned int *)0x8C0F = 0x8005;

위 의 코드를 살펴보면 같은 주소값을 상대로 쓰기가 반복적으로 이루어 진다. 이 코드를 수행한 후에는 최종적으로 0x8C0F주소에 0x8005값만 남아있을 것이다. 이 경우 컴파일러는 최적화를 위해 이전의 코드를 실행 안하고 맨마지막 코드만 실행 시키는데, 프로세서의 레지스터에 값을 써서 제어하는 경우 오작동이 일어날 수 있다.
이 경우, volatile 키워드를 사용하면 컴파일러가 최적화하는 것을 방지해서 오작동하는 것을 막을 수 있다.

*(volatile unsigned int *)0x8C0F = 0x8001;
*(volatile unsigned int *)0x8C0F = 0x8002;
*(volatile unsigned int *)0x8C0F = 0x8003;
*(volatile unsigned int *)0x8C0F = 0x8004;
*(volatile unsigned int *)0x8C0F = 0x8005; "

이런 글인데, "프로세서의 레지스터에 값을 써서 제어" 한다는게 잘 이해가 안가네요. 프로세서 관점으로 봤을때 최적화된 첫번째 코드는 레지스터에 값을 써서 제어하는거고 volatile 써서 최적화 안된 두번째 코드는 레지스터에 값을 쓰지 않고 어떤식으로 제어를 하는건가요?

긴글 읽어주셔서 감사합니다 :)

익명 사용자의 이미지

1. 둘 다 레지스터에 값을 써서 제어 "하려는" 코드입니다.

2. 첫 번째 코드의 경우, 컴파일러는 0x8c0f에 있는 것을 그냥 메모리의 일부로 간주합니다. 그러면 0x8001~0x8005를 차례로 대입해 줄 필요가 없습니다. 그렇게 한 셈치고 0x8005를 한 번만 대입해 주면 됩니다.

(1) 왜 그렇게 해도 되는지 설명하려면 무척 길어집니다. C/C++언어를 "로우 레벨 언어"로써 쓰고 계신 분들은, 대체로 이 언어들이 컴파일러에 어느 정도의 재량을 허용하는지 정확하게 숙지할 필요가 있지요.

3. 두 번째 코드의 경우, 컴파일러는 그런 최적화를 수행할 수 없습니다.

주어진 예시는, 프로그래머의 의도에 따라 0x8001~0x8005를 차례로 대입하는 것이 "반드시" 필요한 경우를 다루고 있는 겁니다. 즉 volatile을 써서 후자와 같이 코딩해야 하는 것이죠.

Anti-Lock의 이미지

레지스터라는 것이 이렇게 2종류가 있다고 생각하시면 됩니다.
1. 범용 레지스터: 이것은 보통 일반적인 연산을 위한 임시저장장소로 보시면 됩니다.
2. 특수 레지스터: 1번이 아닌 레지스터로 정의 할수 있겠습니다. 주로 I/O 장치들을 다루기 위한 레지스터들을 말하는데, 이들 레지스터는 연산을 위한 위한 용도가 아니라, 특정 동작을 위하여 값을 쓰는(write or read) 하는 경우가 대부분입니다. 예를 들어 0x8c0f 주소가 FIFO 주소인경우, FIFO 레지스터라고 하기도 하며, 여기에 0x8001~0x8005 차례대로 여러번 써 넣는것은 0x8005 를 한번만 써 넣는것과는 매우 다른 동작입니다.

비록 설명이 정확하지는 않을 수 있습니다만, 이해하시는데 어려움은 없을것 같습니다.

Necromancer의 이미지

volatile은 OOO(Out-Of-Order)와 캐시에 관련이 있는 지시어입니다.

OOO는 CPU 클럭속도 올리는거에 한계가 왔으니 CPU에서 결과가 뒤바뀌지 않는 한도 내에서 명령어 실행 순서를 임의로 바꿔 실행하는 기술이고(예를 들자면 첫번째 복잡한 명령 뒤에 단순한 명령어 여럿이 올 경우 뒤의 단순한 명령어 여러 개를 먼저 해버리고 첫번째 복잡한 명령 처리하는 식), 캐시는 CPU가 따라가지 못하는 메모리 속도를 보조하기 위해서 들어간 기술인데, 시점에 따른 값의 세팅이 확실해야 하는 제어 쪽에서는 이게 심각한 문제를 일으키는 경우가 매우 많습니다.

volatile이 있다면 컴파일러가 해당 변수에 대해 읽기 쓰기 순서를 확실하게 보장하도록 코드를 생성하게 됩니다. 해당 변수에 접근하게 되면 OOO가 동작하지 않고, 다중프로세서 환경이라면 캐시 처리시에도 순서가 확실히 보장되도록 특별한 절차가 더 들어가는 코드가 생성됩니다.

그리고 본문글 내용은 프로세서 레지스터를 Memory-Mapped I/O로 사용하는 경우입니다.
Memory-Mapped I/O로 사용하는 경우 특정 메모리 주소가 특정 레지스터와 연결되어 있어서 CPU에서 그 주소의 메모리에 접근하면 메모리가 아닌 레지스터로 쓴값이 날라갑니다.

레지스터로 어떤 기능을 제어하는데, 레지스터가 Memory-Mapped I/O로 접근되고, 그 순서를 확실히 지켜야 한다면 CPU의 OOO와 캐시 영향이 안가도록 확실하게 할 필요가 있습니다.

임베디드가 아니더라도 Memory-Mapped I/O 엄청나게 많이 쓰고 있습니다.
비디오카드 VRAM이 대표적입니다. 도스시절 0xA0000~0xBFFFF사이 주소를 읽고 쓰면 비디오카드 VRAM으로 날라가서 그 내용에 따라 화면이 표시됐고, VGA카드도 화면 표시모드, 해상도 등의 설정을 위해 수많은 레지스터를 가지고 있습니다. 가짓수가 CPU보다 더 많을겁니다.

Written By the Black Knight of Destruction

익명 사용자의 이미지

Quote:
volatile이 있다면 컴파일러가 해당 변수에 대해 읽기 쓰기 순서를 확실하게 보장하도록 코드를 생성하게 됩니다. 해당 변수에 접근하게 되면 OOO가 동작하지 않고, 다중프로세서 환경이라면 캐시 처리시에도 순서가 확실히 보장되도록 특별한 절차가 더 들어가는 코드가 생성됩니다.

이 부분은 레퍼런스가 필요합니다.

volatile object access에 대해서 언어 표준이 요구하는 것은 분명히 있습니다만, 그걸 어느 범위까지 어떻게 만족시켜야 하는지는 분명하지 않거든요.

예컨대 MS Visual C++ 같은 경우, volatile object에 대한 read/write는 acquire/release semantics을 보장하기도 합니다: https://docs.microsoft.com/en-us/cpp/cpp/volatile-cpp?view=vs-2019

한편 gcc는 그런 보장이 없지요: https://gcc.gnu.org/onlinedocs/gcc-9.1.0/gcc/Volatiles.html

Anti-Lock의 이미지

공감합니다.
volatile 과 atomic 은 다르지요.(c/c++에서)

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.