This topic has not yet been rated - Rate this topic

volatile (C++)

[This documentation is for preview only, and is subject to change in later releases. Blank topics are included as placeholders.]

The volatile keyword is a type qualifier that's used to declare that an object can be modified in the program by the operating system, the hardware, or a concurrently executing thread.


          
volatile declarator ;
        

The following example declares a volatile integer nVint whose value can be modified by external processes.

int volatile nVint;

Microsoft Specific

Objects that are declared as volatile are not used in certain optimizations because their values can change at any time. The system always reads the current value of a volatile object when it is requested, even if a previous instruction asked for a value from the same object. Also, the value of the object is written immediately on assignment.

When the compiler is optimizing, it must maintain ordering among references to volatile objects in addition to references to other global objects. In particular:

  • A write to a volatile object (volatile write) has Release semantics; a reference to a global or static object that occurs before a write to a volatile object in the instruction sequence will occur before that volatile write in the compiled binary.

  • A read of a volatile object (volatile read) has Acquire semantics; a reference to a global or static object that occurs after a read of volatile memory in the instruction sequence will occur after that volatile read in the compiled binary.

This enables volatile objects to be used for memory locks and releases in multithreaded applications.

Note Note

Although the processor will not reorder un-cacheable memory accesses, un-cacheable variables must be volatile to guarantee that the compiler will not change memory order.

Important note Important

If a struct member is marked as volatile, volatile is propagated to the whole struct. If a struct does not have a length that can be copied on the current architecture by using one instruction, volatile may be completely lost on that struct.

End Microsoft Specific

One use of the volatile qualifier is to provide access to memory locations that are used by asynchronous processes such as interrupt handlers.

Note Note

When it is used on a variable that also has the __restrict keyword, volatile takes precedence.

This program uses two features of volatile memory.

  • It must honor all reads and writes from volatile memory; this enables it to be used for a mutex.

  • It cannot move a reference to global data down across a volatile write; therefore, you can use it to guard a critical section.

  • It cannot move a reference to global data up across a volatile read; this ensures that a critical section is exited before critical data is loaded.


// volatile.cpp
// compile with: /EHsc /O2
#include <iostream>
#include <windows.h>
using namespace std;

volatile bool Sentinel = true;
int CriticalData = 0;

unsigned ThreadFunc1( void* pArguments ) {
   while (Sentinel)
      Sleep(0);   // volatile spin lock

   // CriticalData load guaranteed after every load of Sentinel
   cout << "Critical Data = " << CriticalData << endl;
   return 0;
} 

unsigned  ThreadFunc2( void* pArguments ) {
   Sleep(2000);
   CriticalData++;   // guaranteed to occur before write to Sentinel
   Sentinel = false; // exit critical section
   return 0;
}

int main() {
   HANDLE hThread1, hThread2; 
   DWORD retCode;

   hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&ThreadFunc1,
      NULL, 0, NULL);
   hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&ThreadFunc2,
      NULL, 0, NULL);
   if (hThread1 == NULL || hThread2 == NULL) {
      if (hThread1 != NULL) CloseHandle(hThread1);
      if (hThread2 != NULL) CloseHandle(hThread2);
      cout << "CreateThread failed." << endl; 
      return 1;
   }

   retCode = WaitForSingleObject(hThread1,3000);

   CloseHandle(hThread1);
   CloseHandle(hThread2);

   if (retCode == WAIT_OBJECT_0 && CriticalData == 1 )
      cout << "Success" << endl;
   else
      cout << "Failure" << endl;
}
Critical Data = 1
Success
Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ