왜 휘발성이 존재합니까? volatile할 키워드? C ++에서 어떤 문제가

는 무엇을 않습니다 volatile할 키워드? C ++에서 어떤 문제가 해결됩니까?

제 경우에는 의도적으로 필요하지 않았습니다.



답변

volatile 완전히 분리 된 프로세스 / 장치 / 무엇을 쓸 수 있는지 메모리의 특정 지점에서 읽는 경우 필요합니다.

나는 C에서 멀티 프로세서 시스템에서 듀얼 포트 램을 사용했습니다. 우리는 다른 사람이 언제 완료되었는지 알기 위해 세마포어로 16 비트 값으로 관리되는 하드웨어를 사용했습니다. 본질적으로 우리는 이것을했습니다 :

void waitForSemaphore()
{
   volatile uint16_t* semPtr = WELL_KNOWN_SEM_ADDR;/*well known address to my semaphore*/
   while ((*semPtr) != IS_OK_FOR_ME_TO_PROCEED);
}

이 없으면 volatile옵티마이 저는 루프를 쓸모없는 것으로 간주합니다 (남자는 절대 값을 설정하지 않습니다! 그는 견과류를 제거하고 해당 코드를 제거하십시오!). 내 코드는 세마포어를 얻지 않고 계속 진행되어 나중에 문제가 발생합니다.


답변

volatile내장 시스템 또는 장치 드라이버를 개발할 때 메모리 매핑 된 하드웨어 장치를 읽거나 써야합니다. 특정 장치 레지스터의 내용은 언제든지 변경 될 수 있으므로 volatile이러한 액세스가 컴파일러에 의해 최적화되지 않도록 키워드가 필요합니다 .


답변

일부 프로세서에는 64 비트 이상의 정밀도를 갖는 부동 소수점 레지스터가 있습니다 (예 : SSE가없는 32 비트 x86, Peter의 의견 참조). 이렇게하면 배정 밀도 숫자로 여러 연산을 실행하면 실제로 각 중간 결과를 64 비트로 자르는 것보다 더 정밀한 답변을 얻을 수 있습니다.

이것은 일반적으로 훌륭하지만 컴파일러가 레지스터를 할당하고 최적화를 수행 한 방법에 따라 정확히 동일한 입력에 대해 동일한 작업에 대해 다른 결과를 갖게됨을 의미합니다. 일관성이 필요한 경우 volatile 키워드를 사용하여 각 작업을 강제로 메모리로 되돌릴 수 있습니다.

대수적으로 이해하지 않지만 Kahan summation과 같은 부동 소수점 오류를 줄이는 일부 알고리즘에도 유용합니다. 대수적으로 그것은 nop이므로 일부 중간 변수가 휘발성이 아닌 한 종종 잘못 최적화됩니다.


답변

A로부터 “휘발성 약속으로” 단 삭스에 의해 기사 :

(…) 휘발성 개체는 값이 자연스럽게 변경 될 수있는 개체입니다. 즉, 객체를 휘발성으로 선언하면 프로그램의 명령문이 객체를 변경하는 것으로 보이지 않더라도 객체가 상태를 변경할 수 있음을 컴파일러에 알립니다. “

다음은 volatile키워드 에 관한 세 가지 기사의 링크입니다 .


답변

잠금없는 데이터 구조를 구현할 때는 반드시 휘발성을 사용해야합니다. 그렇지 않으면 컴파일러는 변수에 대한 액세스를 자유롭게 최적화하여 의미를 변경합니다.

달리 말하면, volatile은이 변수에 액세스하는 컴파일러가 실제 메모리 읽기 / 쓰기 작업에 해당해야한다는 것을 컴파일러에 알려줍니다.

예를 들어, Win32 API에서 InterlockedIncrement를 선언하는 방법은 다음과 같습니다.

LONG __cdecl InterlockedIncrement(
  __inout  LONG volatile *Addend
);

답변

1990 년대 초에 작업했던 대규모 응용 프로그램에는 setjmp 및 longjmp를 사용하는 C 기반 예외 처리가 포함되었습니다. 휘발성 키워드는 “catch”절 역할을하는 코드 블록에 값을 유지해야하는 변수에 필요했습니다. 이러한 변수는 레지스터에 저장되고 longjmp에 의해 삭제되지 않습니다.


답변

표준 C에서 사용할 장소 중 하나 volatile는 신호 처리기입니다. 실제로 표준 C에서 신호 처리기에서 안전하게 할 수있는 모든 것은 volatile sig_atomic_t변수를 수정 하거나 빠르게 종료하는 것입니다. 실제로 AFAIK는 표준 C에서 volatile정의되지 않은 동작을 피하기 위해 사용해야하는 유일한 장소입니다 .

ISO / IEC 9899 : 2011 §7.14.1.1 signal기능

¶5 abort또는 raise함수 호출의 결과가 아닌 다른 신호가 발생하는 경우, 신호 핸들러가 값을 지정하는 것 이외의 잠금없는 원자 오브젝트가 아닌 정적 또는 스레드 저장 기간을 갖는 오브젝트를 참조하면 동작이 정의되지 않습니다. 로 선언 된 객체 volatile sig_atomic_t에 신호 를 보내 거나 신호 핸들러는 표준 라이브러리에서 abort함수, _Exit함수,
quick_exit함수 또는 signal첫 번째 인수 가 함수를 호출하는 원인이되는 신호에 해당하는 신호 번호와 다른 함수 이외의 함수를 호출합니다. 매니저. 또한 이러한 signal함수 호출로 인해 SIG_ERR 리턴이 발생하면 값 errno이 결정되지 않습니다. 252)

252) 비동기 신호 처리기에서 신호를 생성하면 동작이 정의되지 않습니다.

이는 표준 C에서 다음을 작성할 수 있음을 의미합니다.

static volatile sig_atomic_t sig_num = 0;

static void sig_handler(int signum)
{
    signal(signum, sig_handler);
    sig_num = signum;
}

그다지 많지 않습니다.

POSIX는 신호 처리기에서 수행 할 수있는 작업에 대해 훨씬 관대하지만 여전히 제한 사항이 있습니다 (한 가지 제한 사항 중 하나는 표준 I / O 라이브러리 (예 : printf()기타)는 안전하게 사용할 수 없음).