Export (0) Print
Expand All
2 out of 3 rated this helpful - Rate this topic

volatile (C++)

The volatile keyword is a type qualifier used to declare that an object can be modified in the program by something such as 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 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 at the point 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 optimizing, the compiler must maintain ordering among references to volatile objects as well as 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 allows volatile objects to be used for memory locks and releases in multithreaded applications.

NoteNote

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 noteImportant

If a struct does not have a length that can be copied on the current architecture by using one instruction, volatile may be lost on that struct.

End Microsoft Specific

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

NoteNote

When used on a variable that also has the __restrict keyword, volatile will take precedence.

This program uses two features of volatile memory.

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

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

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


// 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)
Thank you for your feedback

Community Additions

ADD
Show:
© 2014 Microsoft. All rights reserved.