휘발성(컴퓨터 프로그래밍)

volatile (computer programming)


컴퓨터 프로그래밍에서, 특히 C, C++, C#, 자바프로그래밍 언어에서, 휘발성 워드는 이 수정되는 것처럼 보이지 않더라도, 다른 액세스 사이에서 변경될 수 있음을 나타낸다.이 키워드는 최적화 컴파일러가 후속 읽기 또는 쓰기를 최적화하는 것을 방지하여 오래된 값을 잘못 재사용하거나 쓰기를 생략하는 것을 방지한다.휘발성 값은 주로 주변 장치와의 통신에 읽기 또는 쓰기를 사용하는 하드웨어 액세스(메모리입출력)와 다른 스레드가 값을 수정했을 수 있는 스레딩에서 발생한다.

공통의 키워드임에도 불구하고 의 행태는.volatile프로그래밍 언어 간에 현저한 차이가 있으며, 쉽게 오해받을 수 있다.C와 C++에서는 다음과 같은 형식 한정자다.const, 그리고 타입의 속성이다.더욱이, C와 C++에서는 대부분의 스레딩 시나리오에서는 작동하지 않으며, 그러한 사용은 금지된다.자바와 C#에서는 변수의 속성이며, 변수가 묶인 객체가 돌연변이를 일으킬 수 있음을 나타내며, 특히 스레딩을 목적으로 한다.D 프로그래밍 언어에는 별도의 키워드가 있다.shared스레딩 용도의 경우, 그러나 novolatile키워드가 있다.

C 및 C++인 경우

C에서, 그리고 결과적으로 C++에서는volatile키워드는 의도된[1] 것이었다.

  • 메모리 매핑된 I/O 장치에 대한 액세스 허용
  • 사이의 변수 사용을 허용하다setjmp그리고longjmp
  • 의 사용을 허락하다sig_atomic_t신호 처리기의 변수

C와 C++ 모두 의도한 것이지만, C 표준은 다음과 같은 것을 표현하지 못한다.volatile의미론(semantics)은 참조된 객체가 아닌 l값을 가리킨다.각각의 결함 보고서인 DR 476 (C11에 대한)은 C17과 함께 여전히 검토 중에 있다.[2]

작업:volatile변수는 원자적이지 않으며, 스레딩에 대한 적절한 발생 전 관계를 설정하지 않는다.이는 관련 표준(C, C++, POSIX, WIN32)에 명시되어 있으며,[1] 휘발성 변수는 대부분의 현재 구현에서 안전하지 않다.따라서, 의 사용법volatile휴대용 동기화 메커니즘으로서의 키워드는 많은 C/C++ 그룹에 의해 좌절된다.[3][4][5]

C에서 메모리 매핑된 I/O의 예

이 예에서 코드는 에 저장된 값을 설정한다.foo0. 그런 다음 로 바뀔 때까지 반복적으로 그 값을 폴링하기 시작한다.255:

정태의 안쪽에 foo;  공허하게 하다 술집을 내다(공허하게 하다) {     foo = 0;      하는 동안에 (foo != 255)          ; } 

최적화 컴파일러는 다른 어떤 코드도 에 저장된 값을 변경할 수 없다는 것을 알게 될 것이다.foo, 그리고 그것이 계속 다음과 같을 것이라고 가정할 것이다.0언제나따라서 컴파일러는 기능 본체를 다음과 유사한 무한 루프(infinite loop)로 교체한다.

공허하게 하다 bar_최적화된(공허하게 하다) {     foo = 0;      하는 동안에 (진실의)          ; } 

하지만fooCPU에 연결된 장치의 하드웨어 레지스터와 같은 컴퓨터 시스템의 다른 요소에 의해 언제든지 변경될 수 있는 위치를 나타낼 수 있다.위의 코드는 그러한 변화를 감지하지 못할 것이다.volatile키워드, 컴파일러는 현재 프로그램이 값을 변경할 수 있는 유일한 부분(이것은 단연코 가장 흔한 상황)이라고 가정한다.

컴파일러가 위와 같이 코드를 최적화하는 것을 방지하려면volatile키워드 사용:

정태의 휘발성이 있는 안쪽에 foo;  공허하게 하다 술집을 내다 (공허하게 하다) {     foo = 0;      하는 동안에 (foo != 255)         ; } 

이 수정으로 루프 상태는 최적화되지 않을 것이며, 시스템은 변화가 발생할 때 변화를 감지할 것이다.

일반적으로 플랫폼(C++11에서 노출되는)에서 사용할 수 있는 메모리 장벽 연산이 있는데, 이는 컴파일러가 더 나은 최적화를 수행할 수 있도록 해주고 더 중요한 것은 C 규격(C11 이전)이나 C++ 특수성(C++)이 아닌 다중 스레드 시나리오에서 올바른 동작을 보장하기 때문에 휘발성 대신 선호해야 한다.n (C++11 이전)은 다중 스레드 메모리 모델을 지정하여 OS/컴파일러/CPU 간에 휘발성이 결정적으로 작용하지 않을 수 있다.[6]

C에서의 최적화 비교

다음 C 프로그램과 함께 제공된 어셈블리는volatile키워드는 컴파일러의 출력에 영향을 미친다.이 사건의 편찬자는 GCC였다.

조립 코드를 관찰하는 동안, 코드는 다음과 같이 생성되는 것이 선명하게 보인다.volatile사물은 좀더 장황하게 되어, 더 길어져서 의 본질이 된다.volatile사물은 성취될 수 있다.volatile키워드는 컴파일러가 휘발성 객체를 포함하는 코드에서 최적화를 수행하지 못하도록 하여 각 휘발성 변수 할당 및 읽기에 해당하는 메모리 액세스를 보장한다.다음이 없는volatile키워드, 컴파일러는 변수를 다른 스레드나 프로세스에서 메모리 위치에 쓰기가 없어야 하기 때문에 각 사용 시마다 메모리에서 다시 읽을 필요가 없다는 것을 알고 있다.

C++11

C++11 ISO 표준에 따르면 휘발성 키워드는 하드웨어 액세스 전용이므로 스레드 간 통신에는 사용하지 마십시오.표준 라이브러리는 스레드 간 통신을 위해std::atomic<T>템플릿[7]

자바에서

자바 프로그래밍 언어에는 또한volatile키워드, 그러나 그것은 다소 다른 목적으로 사용된다.필드에 적용할 때 Java 한정자volatile다음과 같은 보증을 제공한다.

  • 모든 버전의 Java에서는 모든 휘발성 변수의 읽기 및 쓰기(볼라타일에 대한 이 전역 순서는 큰 동기화 순서(모든 동기화 작업에 대한 전체 순서)보다 부분적인 순서)가 있다.이는 휘발성 필드에 액세스하는 모든 스레드가 캐시된 값을 사용하는 대신 계속하기 전에 현재 값을 읽게 된다는 것을 의미한다.(단, 휘발성 읽기 및 쓰기의 상대적 순서에 대해서는 정기적인 읽기 및 쓰기를 보장하지 않으며, 이는 일반적으로 유용한 스레딩 구조가 아니라는 것을 의미한다.)
  • Java 5 이상에서 휘발성 읽기 및 쓰기는 뮤텍스를 획득하고 해제하는 것과 마찬가지로 발생 전 관계를 설정한다.[8][9]

사용.volatile자물쇠보다 빠를 수도 있지만, 자바 5 이전의 어떤 상황에서는 작동하지 않을 것이다.[10]휘발성이 효과적인 상황의 범위는 자바 5에서 확장되었다. 특히, 이중 체크된 잠금이 이제 올바르게 작동한다.[11]

인 C#

C#에서는volatile필드에 액세스하는 코드가 컴파일러, CLR 또는 하드웨어에 의해 수행될 수 있는 일부 스레드 안전하지 않은 최적화의 영향을 받지 않도록 보장한다.필드가 표시된 경우volatile컴파일러는 그 주위에 "메모리 장벽" 또는 "메모리 장벽"을 생성하도록 지시되어, 명령어 재주문 또는 필드에 묶인 캐싱을 방지한다.a를 읽을 때volatile필드, 컴파일러는 다른 스레드에 있는 읽기 및 쓰기를 포함하여 필드로의 다른 읽기 및 쓰기가 울타리 에 이동하는 것을 방지하는 획득-프로세서를 생성한다.에 쓸 때volatilefield, 컴파일러는 release-reason을 생성한다; 이 fence는 fence 다음에 field에 다른 읽기와 쓰기가 이동하는 것을 막는다.[12]

다음 유형만 표시할 수 있음volatile: 모든 참조 유형,Single,Boolean,Byte,SByte,Int16,UInt16,Int32,UInt32,Char, 및 의 기본 유형이 포함된 모든 열거된 유형Byte,SByte,Int16,UInt16,Int32또는UInt32.[13] (이것은 원시 유형뿐만 아니라 가치 구조도 제외한다.Double,Int64,UInt64그리고Decimal.)

사용volatile키워드는 참조로 전달되거나 로컬 변수를 캡처한 필드를 지원하지 않음. 이 경우Thread.VolatileRead그리고Thread.VolatileWrite대신 사용해야 한다.[12]

실제로 이러한 방법은 C# 컴파일러, JIT 컴파일러 또는 CPU 자체에 의해 수행되는 일부 최적화를 비활성화한다.에 의해 제공된 보증Thread.VolatileRead그리고Thread.VolatileWrite에 의해 제공된 보증의 상위 집합이다.volatile키워드: "반쪽 울타리"를 생성하는 대신(즉, 획득-획득은 명령 순서 변경 및 캐싱을 미리 차단할 뿐),VolatileRead그리고VolatileWrite양쪽 방향으로 해당 필드의 순서 변경 및 캐싱을 방지하는 "전체 펜스"를 생성한다.[12]이러한 방법은 다음과 같이 작용한다.[14]

  • Thread.VolatileWrite메소드는 호출 지점에 필드 값을 기록하도록 강제한다.또한, 모든 초기 프로그램 주문 로드 및 스토어는 다음 호출을 수행하기 전에 발생해야 한다.VolatileWrite그리고 나중에 프로그램 주문 로드 및 스토어는 통화 후에 발생해야 한다.
  • Thread.VolatileRead메소드는 호출 지점에서 필드의 값을 읽도록 강제한다.또한, 모든 초기 프로그램 주문 로드 및 스토어는 다음 호출을 수행하기 전에 발생해야 한다.VolatileRead그리고 나중에 프로그램 주문 로드 및 스토어는 통화 후에 발생해야 한다.

Thread.VolatileRead그리고Thread.VolatileWrite메소드들은 그 사람들을 불러내서 완전한 울타리를 만들어낸다.Thread.MemoryBarrier양방향으로 작동하는 기억장벽을 구성하는 방법.위에 주어진 완전한 울타리 사용에 대한 동기 외에, 잠재적인 문제점은 다음과 같다.volatile에 의해 생성된 전체 펜스를 사용하여 해결되는 키워드Thread.MemoryBarrier다음과 같다: 하프 펜스의 비대칭적 성질 때문에volatile읽기 명령이 뒤따르는 쓰기 명령이 있는 필드는 여전히 컴파일러에 의해 실행 순서를 바꿀 수 있다.풀펜스는 대칭이기 때문에 사용 시 문제가 되지 않는다.Thread.MemoryBarrier.[12]

인 포트란

VOLATILE이전 버전이 확장 버전으로서 지원하기는 했지만,[15] Fortran 2003 표준의 일부분이다.모든 변수 만들기volatile함수에서 앨리어싱 관련 버그를 찾는 것도 유용하다.

정수의, 휘발성이 있는 :: i ! 휘발성이 정의되지 않은 경우 다음 두 코드 라인은 동일함 글씨를 쓰다(*,*) i**2  ! 변수 i를 메모리에서 한 번 로드하고 시간 자체를 값을 곱함 글씨를 쓰다(*,*) i*i   ! 변수 i를 메모리에서 두 번 로드하고 해당 값을 곱함 

휘발성 메모리에 항상 "드릴다운"함으로써, Fortran 컴파일러는 볼륨에 대한 읽기 또는 쓰기의 순서를 변경할 수 없다.이렇게 하면 이 스레드에서 수행된 다른 스레드 동작이 눈에 띄게 되며, 그 반대의 경우도 마찬가지다.[16]

휘발성의 사용은 최적화를 방지하고 심지어 감소시킬 수 있다.[17]

참조

  1. ^ a b "Publication on C++ standards committee".
  2. ^ C11에 대한 설명 요청 요약.버전 1.13 2017년 10월.
  3. ^ "Volatile Keyword In Visual C++". Microsoft MSDN.
  4. ^ "Linux Kernel Documentation – Why the "volatile" type class should not be used". kernel.org.
  5. ^ Scott Meyers; Andrei Alexandrescu (2004). "C++ and the Perils of Double-Checked Locking" (PDF). DDJ.
  6. ^ Jeremy Andrews (2007). "Linux: Volatile Superstition". kerneltrap.org. Archived from the original on 2010-06-20. Retrieved Jan 9, 2011.
  7. ^ "volatile (C++)". Microsoft MSDN.
  8. ^ 17.4.4: 동기화 순서
  9. ^ "Java Concurrency: Understanding the 'Volatile' Keyword". dzone.com. 2021-03-08. Archived from the original on 2021-05-09. Retrieved 2021-05-09.
  10. ^ Jeremy Manson; Brian Goetz (February 2004). "JSR 133 (Java Memory Model) FAQ". Archived from the original on 2021-05-09. Retrieved 2019-11-05.
  11. ^ Neil Coffey. "Double-checked Locking (DCL) and how to fix it". Javamex. Retrieved 2009-09-19.
  12. ^ a b c d Albahari, Joseph. "Part 4: Advanced Threading". Threading in C#. O'Reilly Media. Archived (PDF) from the original on 27 April 2011. Retrieved 9 December 2019.
  13. ^ Richter, Jeffrey (February 11, 2010). "Chapter 7: Constants and Fields". CLR Via C#. Microsoft Press. pp. 183. ISBN 978-0-7356-2704-8.
  14. ^ Richter, Jeffrey (February 11, 2010). "Chapter 28: Primitive Thread Synchronization Constructs". CLR Via C#. Microsoft Press. pp. 797–803. ISBN 978-0-7356-2704-8.
  15. ^ "VOLATILE Attribute and Statement". Cray.
  16. ^ "Volatile and shared array in Fortran". Intel.com.
  17. ^ "VOLATILE". Oracle.com.

외부 링크