문제

파일 범위에서 정적 글로벌 변수와 정적 휘발 변수를 사용했습니다.

둘 다 ISR로 업데이트되고 기본 루프 및 기본 루프는 변수의 값을 확인합니다.

여기서 최적화 동안 글로벌 변수 나 휘발성 변수는 최적화되지 않습니다. 따라서 휘발성 변수를 사용하는 대신 글로벌 변수가 문제를 해결합니다.

그렇다면 휘발성 대신 글로벌 변수를 사용하는 것이 좋습니까?

정적 휘발성을 사용해야 할 특정 이유 ??

모든 예제 프로그램은 감사 할 수 있습니다.

미리 감사합니다 ..

도움이 되었습니까?

해결책

그들은 다른 것입니다. 저는 휘발성 의미론 전문가가 아닙니다. 그러나 나는 여기에 설명 된 내용이 의미가 있다고 생각합니다.

글로벌

글로벌 단지 문제의 식별자가 파일 스코프에서 선언 된 것을 의미합니다. 함수 (GOTO-LABELS가 정의되는 경우), 파일 (글로벌이있는 곳), 블록 (일반 로컬 변수가있는 경우) 및 기능 프로토 타입 (기능 매개 변수가있는 경우)이라고하는 스코프가 다릅니다. 이 개념은 식별자의 가시성을 구성하기 위해 존재합니다. 최적화와 관련이 없습니다.

공전

static 저장 시간 (여기서는 보지 않음)이며 파일 범위 내부 링크 내에서 선언 된 이름을 제시하는 방법입니다. 이것은 하나의 번역 단위 내에서만 필요한 함수 또는 객체에 대해 수행 할 수 있습니다. 전형적인 예는 a help 허용되는 매개 변수를 인쇄하고 main 동일하게 정의 된 함수 .c 파일.

6.2.2/2 C99 초안에서 :

객체 또는 함수에 대한 파일 범위의 선언에 스토리지 클래스 사양 정적이 포함 된 경우 식별자는 내부 연결을 갖습니다.

내부 연결은 식별자가 현재 번역 장치 외부에 표시되지 않음을 의미합니다 ( help 위의 기능).

휘발성 물질

휘발성은 다른 것입니다 : (6.7.3/6)

휘발성이 부여 된 유형을 갖는 객체는 구현에 알려지지 않은 방식으로 수정 될 수 있거나 다른 알려지지 않은 부작용이 있습니다. 따라서 이러한 객체를 참조하는 모든 표현은 5.1.2.3에 설명 된 바와 같이 추상 기계의 규칙에 따라 엄격하게 평가되어야한다. 또한, 모든 시퀀스 지점에서 객체에 마지막으로 저장된 값은 이전에 언급 된 미지의 요인에 의해 수정 된 것을 제외하고는 추상 기계에 의해 규정 된 것과 동의해야한다.

표준은 volatile 중복 될 것입니다 (5.1.2.3/8):

구현은 추상과 실제 의미론 사이의 일대일 대응을 정의 할 수 있습니다. 모든 시퀀스 지점에서 실제 객체의 값은 추상적 의미에 의해 지정된 객체와 일치합니다. 키워드 volatile그런 다음 중복됩니다.

시퀀스 포인트는 추상 기계 완료됩니다 (예 : 메모리 셀 값과 같은 외부 조건은 포함되지 않습니다). 오른쪽과 왼쪽 사이 && 그리고 ||, 후에 ; 함수 호출에서 돌아 오는 것은 예를 들어 시퀀스 포인트입니다.

그만큼 초록 의미론 컴파일러가 특정 프로그램 내에서 코드 시퀀스 만 볼 수없는 것입니다. 최적화의 영향은 여기서 관련이 없습니다. 실제 의미론 객체에 글을 쓰면서 수행 한 부작용 (예 : 메모리 셀 변경)을 포함합니다. 휘발성으로 객체 자격을 갖추는 것은 항상 메모리에서 객체의 값을 항상 얻는다는 것을 의미합니다 ( "알 수없는 요소로 수정 된대로"). 표준은 어디서나 스레드를 언급하지 않으며, 변경 순서 또는 작업 원자에 의존 해야하는 경우 플랫폼 종속 방법을 사용하여이를 확인해야합니다.

이해하기 쉬운 개요를 위해 인텔은 그것에 대한 훌륭한 기사를 가지고 있습니다. 여기.

지금 무엇을해야합니까?

파일 스코프 (글로벌) 데이터를 휘발성으로 계속 선언하십시오. 글로벌 데이터 자체가 변수의 값이 메모리에 저장된 값과 같다는 것을 의미하지는 않습니다. 그리고 정적은 객체를 현재 번역 장치 (현재)에 로컬로 만듭니다. .c 파일 및 기타 모든 파일 #에 포함).

다른 팁

먼저 정적 글로벌 변수는 변수를 파일의 범위로 제한한다는 점을 제외하고는 글로벌 변수와 동일하다는 것을 언급하겠습니다. 즉,이 글로벌 변수를 다른 파일에서 사용할 수 없습니다. extern 예어.

따라서 질문을 글로벌 변수 대 휘발성 변수로 줄일 수 있습니다.

이제 휘발성 :

처럼 const, volatile 유형 수정 자입니다.

그만큼 volatile 키워드는 특히 비동기 이벤트가있을 때 코드가 잘못 될 수있는 컴파일러 최적화를 방지하기 위해 만들어졌습니다.

대상이 선언되었습니다 volatile 특정 최적화에는 사용되지 않을 수 있습니다.

이 시스템은 이전 명령이 동일한 객체에서 값을 요구하더라도 사용되는 시점에서 휘발성 객체의 현재 실제 값을 항상 읽습니다. 또한 객체의 값은 할당시 즉시 기록됩니다. 즉, 휘발성 변수를 CPU 레지스터로 캐싱하지 않음을 의미합니다.

Jobb 박사는 휘발성에 대한 훌륭한 기사를 가지고 있습니다.

다음은 Dr. Jobb의 기사의 예입니다.

class Gadget
{
public:
    void Wait()
    {
        while (!flag_)
        {
            Sleep(1000); // sleeps for 1000 milliseconds
        }
    }
    void Wakeup()
    {
        flag_ = true;
    }
    ...
private:
    bool flag_;
};

컴파일러가 그것을 본다면 Sleep() 외부 호출입니다 Sleep() 변수 flag_의 값을 변경할 수 없습니다. 따라서 컴파일러는 값을 저장할 수 있습니다 flag_ 레지스터에서. 그리고이 경우에는 결코 변하지 않을 것입니다. 그러나 다른 스레드가 Wakeup을 호출하면 첫 번째 스레드는 여전히 CPU 레지스터에서 읽고 있습니다. Wait() 결코 일어나지 않을 것입니다.

그렇다면 변수를 레지스터로 캐시하지 않고 문제를 완전히 피하지 않겠습니까? 이 최적화는 전반적으로 많은 시간을 절약 할 수 있다는 것이 밝혀졌습니다. 따라서 C/C ++는 volatile 예어.

위의 사실 flag_ 회원 변수였으며 글로벌 변수 (또는 정적 글로벌)가 아닌 것은 중요하지 않습니다. 예제 후의 설명은 글로벌 변수 (및 정적 글로벌 변수)를 다루더라도 올바른 추론을 제공합니다.

일반적인 오해는 변수를 선언하는 것입니다 volatile 스레드 안전을 보장하기에 충분합니다. 변수의 작업은 레지스터에서 "캐시"되지 않더라도 여전히 원자가되지 않습니다.

포인터와의 휘발성 :

포인터와의 휘발성, 포인터와 함께 Const처럼 작동합니다.

유형의 변수 volatile int * 포인터가 가리키는 변수가 휘발성임을 의미합니다.

유형의 변수 int * volatile 포인터 자체가 휘발성이라는 것을 의미합니다.

"휘발성"키워드는 컴파일러가 해당 변수와 관련된 코드에 대한 특정 최적화를 수행하지 않도록 제안합니다. 글로벌 변수 만 사용하는 경우 컴파일러가 코드를 잘못 최적화하는 것을 방지하는 것은 없습니다.

예시:

#define MYPORT 0xDEADB33F

volatile char *portptr = (char*)MYPORT;
*portptr = 'A';
*portptr = 'B';

"휘발성"이 없으면 첫 번째 쓰기가 최적화 될 수 있습니다.

휘발성 키워드는 변수가 캐시되지 않도록 컴파일러에게 지시합니다. 모든 액세스는 모든 스레드 사이에 일관된 값을 갖도록 일관된 방식으로 이루어져야합니다. 루프가 변경 사항을 확인하는 동안 변수의 값이 다른 스레드로 변경되는 경우, 어느 지점과 루프에서 일반 변수 값이 캐시되지 않을 것이라는 보장이 없으므로 변수가 휘발성이되기를 원합니다. 단지 그것이 동일하게 유지된다고 가정 할 것입니다.

Wikipedia의 휘발성 변수

현재 환경에서는 다르지 않을 수 있지만 미묘한 변화는 행동에 영향을 줄 수 있습니다.

  • 다른 하드웨어 (더 많은 프로세서, 다른 메모리 아키텍처)
  • 더 나은 최적화로 컴파일러의 새로운 버전.
  • 스레드 사이의 타이밍의 임의의 변화. 문제는 1 천만에서 한 번만 발생할 수 있습니다.
  • 다른 컴파일러 최적화 설정.

장기적으로는 처음부터 적절한 멀티 스레딩 구성을 사용하는 것이 훨씬 안전합니다.

물론 프로그램이 멀티 스레드가 아닌 경우 중요하지 않습니다.

i +1 Friol의 대답. 다른 답변에 많은 혼란이있는 것처럼 보이므로 약간의 정밀도를 추가하고 싶습니다. C의 휘발성은 Java의 휘발성이 아닙니다.

먼저, 컴파일러는 프로그램의 데이터 흐름을 기반으로 많은 최적화를 수행 할 수 있습니다. C의 휘발성을 방지합니다. 예를 들어 닦는 레지스터를 사용하는 대신 매번 위치에 실제로로드/저장해야합니다). . Friol이 지적한 것처럼 메모리 매핑 IO 포트가있을 때 유용합니다.

C의 휘발성은 하드웨어 캐시 또는 멀티 스레딩과 관련이 없습니다. 메모리 울타리를 삽입하지 않으며 두 스레드가 액세스하는 경우 작업 순서에 대해 전혀 garanty가 없습니다. Java의 휘발성 키워드는 정확히 다음과 같습니다. 필요한 경우 메모리 울타리 삽입.

휘발성 변수는 휘발 된 값이 일정하지 않음을 의미합니다. 즉 휘발성 변수 "a = 10"을 포함하는 함수가 해당 함수의 각 호출에 1을 추가하는 경우 항상 업데이트 된 값을 반환합니다.{ volatile int a=10; a++; }위의 함수가 계속해서 호출되면 변수 a는 10으로 다시 시작되지 않으면 프로그램이 실행될 때까지 항상 업데이트 된 값을 표시합니다. 첫 번째 출력 = 10 그런 다음 11 그 다음 12 등.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top