Looking for something specific?
  Home
Home
Articles
Page Tag-Cloud
  Software
Software Tag-Cloud
Building from Source
Open Source Definition
All Software
  Popular Tags
Legacy
C Plus Plus
Source Code
Class
Cryptography
  Members
Login
Web-Email
Notable Members
  Official
Our Company
Copyright Information
Software EULA
GPL EULA
LGPL Eula
Pre-Release EULA
Privacy Policy
  Support
Make Contact
 
 
It's not volatile, this is critical

For far too long I have listened to the likes of those who believe that the volatile modifier is the end-all answer to multi-threaded development.
 
Parallelism is complex! Given its complexity, it should not be "screwed with" by any person not understanding the difference between "mutual-exclusive synchronization" and "volatile variables" (CPU cache optimization exclusion).
 
Take the example below, read it, study it, compile it and run it. Once you have satisfied yourself that it will always print the number 5,000,000 to the console as it's only possible output, I would then like you to remove the [EnterCriticalSection] / [LeaveCriticalSection] pair and give the application another run - amazed yet?
 
How can this be, I mean I'm using the volatile modifier? (please note the knee deep puddle of sarcasm)

//-------------------------------------------------------------------------------
#include "windows.h"
#include "stdio.h"
//-------------------------------------------------------------------------------
 
volatile unsigned int iGlobalCounter = 0;
CRITICAL_SECTION CS;
 
//-------------------------------------------------------------------------------
 
DWORD WINAPI threadProc(LPVOID pData)
{
 HANDLE hEvent = (HANDLE) pData; //The synchronization object handle.
 
 //Increment [iGlobalCounter] 1 million times.
 for(unsigned int i = 0; i < 1000000; i++)
 {
  //Comment out [EnterCriticalSection] and [LeaveCriticalSection],
  // which control access to iGlobalCounter to see this
  // multi-threaded example go awry.
 
  EnterCriticalSection(&CS);
  iGlobalCounter++;
  LeaveCriticalSection(&CS);
 }
 
 //Set the synchronization object to let the calling
 // thread know that this workload is complete.
 SetEvent(hEvent);
 
 return 0;
}
 
//-------------------------------------------------------------------------------
 
void IncrementGlobalCounter(void)
{
 int iThreadCount = 5; //Create 5 threads.
 char sEventName[255];
 HANDLE *hEvent = NULL;
 
 //Allocate enough RAM to hold "wait event" handles for each thread.
 if(!(hEvent = (HANDLE *) calloc(sizeof(HANDLE), iThreadCount)))
 {
  printf("Memory allocation error.\n");
  return;
 }
 
 //Initialize a critical section object.
 memset(&CS, 0, sizeof(CS));
 InitializeCriticalSection(&CS);
 
 for(int iThread = 0; iThread < iThreadCount; iThread++)
 {
  //Create a unique event name for a synchronization object.
  sprintf(sEventName, "Thread_Event_%d_%d", GetTickCount(), iThread);
 
  //Create a synchronization object.
  hEvent[iThread] = CreateEvent(NULL, FALSE, FALSE, sEventName);
 
  //Create a thread, passing it the handle to the synchronization object.
  CreateThread(NULL, 0, threadProc, hEvent[iThread], 0, NULL);
 }
 
 //Wait on all threads to complete.
 WaitForMultipleObjects(iThreadCount, hEvent, TRUE, INFINITE);
 
 //Clean up the allocated RAM and the critical section object.
 free(hEvent);
 DeleteCriticalSection(&CS);
}
 
//-------------------------------------------------------------------------------
 
int main(int argc, char *argv[])
{
 //CPU Count and CPU Affinity validation
 SYSTEM_INFO SI;
 memset(&SI, 0, sizeof(SI));
 GetSystemInfo(&SI);
 
 if(SI.dwNumberOfProcessors < 0)
 {
  printf("Your must have more than one CPU core for this example.\n");
  return 1;
 }
 
 //Lets perform the whole test 10 times.
 for(int iTestNumber = 0; iTestNumber < 10; iTestNumber++)
 {
  iGlobalCounter = 0; //Reset the counter to zero.
  
  IncrementGlobalCounter(); //Increment the global counter.
 
  //Output the totaled global counter. It should
  // be 5,000,000 ([5 threads] * [1 million increments]).
  printf("iGlobalCounter: %d\n", iGlobalCounter);
 }
 
 system("Pause");
}
 
//-------------------------------------------------------------------------------


Is this code snippet, product or advice warrantied against ill-effect and/or technical malaise? No. No it's not! Not expressed - Not implied - not at all.




Tags:
 C Plus Plus    Parallel Programming    Threading  

Created by Josh Patterson on 2/8/2013, last modified by Josh Patterson on 2/8/2013

No comments currently exists for this page. Why don't you add one?
First Previous Next Last 

 
Copyright © 2024 NetworkDLS.
All rights reserved.
 
Privacy Policy | Our Company | Contact