C의 휘발성 한정자

Mehvish Ashiq 2023년10월12일
  1. C의 휘발성 한정자
  2. C 프로그래밍에서 휘발성 한정자 사용
C의 휘발성 한정자

오늘의 튜토리얼은 C의 휘발성 한정자에 대해 가르칩니다. 우리는 C 프로그래밍에서 이 한정자를 어디에서 어떻게 사용할 수 있는지 이해할 것입니다.

C의 휘발성 한정자

우리는 저수준 프로그래밍 작업을 할 때까지 휘발성 한정자를 사용하지 않습니다. 여기서 저수준 프로그래밍은 하드웨어와 상호 작용해야 하는 IO 포트 및 ISR(Interrupt Service Routine)을 처리해야 하는 코드를 의미합니다.

우리 모두는 컴파일러가 C 코드를 기계 코드로 변환하여 실행 파일이 소스 코드 없이도 실행될 수 있다는 것을 알고 있습니다.

다른 기술과 마찬가지로 C 프로그래밍용 컴파일러도 소스 코드를 기계 코드로 변환합니다. 여기에서 컴파일러는 일반적으로 결과(출력)를 최적화하기 위해 고군분투하므로 마지막에 최소한의 기계어 코드를 실행해야 합니다.

이러한 종류의 최적화는 컴파일러 관점에서 업데이트되지 않는 변수에 액세스하기 위한 불필요한 기계어 코드를 제거합니다.

예제 코드:

int main() {
  int status = 0;
  while (status == 0) {
  }
}

최적화 컴파일러는 위 코드의 while 루프에서 status라는 변수가 업데이트되지 않음을 관찰합니다. 따라서 각 반복에서 이 변수에 액세스할 필요가 없습니다.

루프는 컴파일러에 의해 무한 루프(while(1))로 변환되므로 status 변수를 읽는 기계 코드가 필요하지 않습니다.

컴파일러는 status 변수가 루프 외부의 어느 시점에서도 현재 프로그램에서 업데이트될 수 있다는 것을 알지 못합니다. 예를 들어, 주변 장치에서 IO 작업이 발생하는 경우입니다.

실질적으로 우리는 컴파일러가 모든 반복에서 status라는 이름의 변수에 액세스하기를 원하지만 프로그램은 변수를 변경하지 않습니다. 이제 이러한 상황을 피하기 위해 이러한 C 프로그램에 대한 모든 컴파일 최적화를 해제하라는 제안이 있을 수 있지만 다음과 같은 이유로 해결책이 아닙니다.

  • 컴파일러의 구현은 서로 다릅니다.
  • 하나의 변수 때문에 모든 컴파일러 최적화를 끄면 이러한 최적화 중 일부가 다른 프로그램 부분에서 필요할 수 있기 때문에 문제가 발생할 수 있습니다.
  • 컴파일러 최적화 해제로 인해 하위 수준 응용 프로그램이 예상대로 작동하지 않습니다. 예를 들어, 지연된 실행.

여기에서 휘발성 한정자가 필요합니다. 휘발성 키워드는 우리가 (프로그래머로서) 상태에 대해 최적화가 허용되지 않음을 컴파일러에 알리기 위해 사용하는 한정자일 뿐이며 다음과 같이 사용됩니다.

volatile int status = 0;

이 한정자를 사용하는 사람은 휘발성의 다음 속성을 고려해야 합니다.

  • 메모리 할당을 제거할 수 없습니다.
  • 변수는 레지스터에 캐시될 수 없습니다.
  • 할당 순서에 따라 값을 변경할 수 없습니다.

C 프로그래밍에서 휘발성 한정자 사용

아래 코드에서는 스레드가 done이라는 변수를 변경할 때까지 "Waiting..." 메시지를 인쇄한 다음 "Okay, let's move on"이라는 또 다른 메시지를 인쇄합니다.

예제 코드(휘발성 제외):

#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>

bool done = false;

void *tfunc() {
  sleep(1);
  done = true;
  return NULL;
}

int main() {
  pthread_t t1;
  pthread_create(&t1, NULL, tfunc, NULL);
  printf("Waiting...\n");
  while (!done) {
  }
  printf("Okay, Let's move on");
}

이 프로그램을 컴파일하고 실행하십시오.

PS C:\Users\DelftStack\Desktop\C> gcc volatile.c -o volatile -lpthread
PS C:\Users\DelftStack\Desktop\C> ./volatile

다음 출력을 보면 정상적으로 예상대로 진행되고 있습니다.

출력:

Waiting...
Okay, Let's move on

이제 동일한 소스 코드에 대해 컴파일러 최적화를 켭니다.

PS C:\Users\DelftStack\Desktop\C> gcc -O3 volatile.c -o volatile -lpthread
PS C:\Users\DelftStack\Desktop\C> ./volatile

아래 출력이 표시되기 때문에 예상대로 작동하지 않습니다.

출력:

Waiting...

컴파일러는 while 루프를 살펴보고 done 변수가 while 루프에서 업데이트되지 않는다는 것을 확인했습니다. 컴파일러는 다른 스레드가 done이라는 전역 변수를 수정한다는 사실을 깨닫지 못하기 때문에 컴파일러는 코드를 변경하고 프로그램을 중단합니다.

여기에서 휘발성 한정자를 사용합니다. 코드를 업데이트하고 done 변수를 volatile로 만듭니다.

예제 코드(휘발성 포함):

#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>

volatile bool done = false;

void *tfunc() {
  sleep(1);
  done = true;
  return NULL;
}

int main() {
  pthread_t t1;
  pthread_create(&t1, NULL, tfunc, NULL);
  printf("Waiting...\n");
  while (!done) {
  }
  printf("Okay, Let's move on");
}

코드는 최적화를 사용해도 잘 작동합니다. 다음을 참조하십시오.

PS C:\Users\DelftStack\Desktop\C> gcc -O3 volatile.c -o volatile -lpthread
PS C:\Users\DelftStack\Desktop\C> ./volatile

출력:

Waiting...
Okay, Let's move on
Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook