Click here to Skip to main content
Licence 
First Posted 6 Mar 2004
Views 28,696
Bookmarked 13 times

Accessing global variable from several thread , show the problems when 2 thread touch the same variable

By | 6 Mar 2004 | Article
When 2 thread are changing global variable without sync , this thing can make problems

Introduction

This example show the problem that 2 thread are touching global variable without sync and solution to the problem.
This example is verry simple one so dont expect to any catches.
THe problem is starting when 2 thread touching global variable and make the operation of g_iNum++.

The problem is that this operation although written in one line , have 3 assembler operation.

1.mov g_iNum ax
2.inc ax
3.mov ax g_iNum

The problem is in case that the context switch between the threads is line number one.

Look at the following thread :


void NotSyncThread(int * a_iNum)
{
 while(g_iGoOn)
 {
  (*a_iNum)++;
  g_iNum++;
 }
}


We are running this 2 threads of this kind and each thread will run N operation .

The expected result is that the global variable g_iNum will have the value of 2*N,
Because this is the number of operation that we are making on him ,

But as U can see from the example this is not like that and in the end we will get
g_iNum <= 2*N

More that I can say is that as long as the process is running g_iNum will be smaller than 2*N.

To solve this problem there are 3 optinal way.

1.First option is to use the function of the O.S InterLockedIncrement ( See function sync1)
this option is clear and there is no need to explain it .
void Sync1(int * a_iNum)
{
 while(g_iGoOn)
 {
  (*a_iNum)++;
  InterlockedIncrement((LPLONG)&g_iNum);  //binary operation,
 }
}
2.Second option is to use mutex,
This function is also well knows

void SyncWithMutex(int * a_iNum)
{
 static HANDLE l_hmProtect=::CreateMutex(NULL,false,NULL);
 if(l_hmProtect==NULL)
 {
  cout<<"There is problem in creating the The mutex\n";
  return ;
 }
 while(g_iGoOn)
 {
  WaitForSingleObject(l_hmProtect,INFINITE);  //starting the critical section,
         //this is the syncronized area
  (*a_iNum)++;
  g_iNum++;
 
  ReleaseMutex(l_hmProtect);

 }
}

The reason that I am using static for the handle of the mutex is because that I want to create it only in case
that the user is calling this function .


3.Thirth way to solv the problem is using semaphore  ,

void SyncWithSemaphore(int * a_iNum)
{
 static HANDLE l_hsProtect=CreateSemaphore(NULL,1,1,NULL);
 if(l_hsProtect==NULL)
 {
  cout<<"There is problem in creating the semaphore\n";
  return ;
 }


 while(g_iGoOn)
 {
  WaitForSingleObject(l_hsProtect,INFINITE);
  (*a_iNum)++;
  g_iNum++;
  ReleaseSemaphore(l_hsProtect,1,NULL);
 }

}

The thirth way is to use semaphore , I will not get into details because this is the same principle as
the second thread.


As I said before this application is for beginer but I think that every programmer should encounter this problem
in real and not in thoery.

The use of (*a_iNum)++; inside the threas is to count how many operation this thread have done.
In the end of the process the sum of the number of the operation should be equal to the global number.

 


Because that I did not know how do I make link to download this program , I will put it here ,
Use copy past to visual studio.
Warning the program will not work in windows 98.


//start copy past from this line


#include<windows.h>
#include<iostream.h>


int g_iNum=0;

int g_iGoOn = 1;
//int g_iFirst = 0;
//int g_iSecond = 0;


void NotSyncThread(int * a_iNum)
{
 while(g_iGoOn)
 {
  (*a_iNum)++;
  g_iNum++;
 }
}


void Sync1(int * a_iNum)
{
 while(g_iGoOn)
 {
  (*a_iNum)++;
  InterlockedIncrement((LPLONG)&g_iNum);
 }
}


void SyncWithMutex(int * a_iNum)
{
 static HANDLE l_hmProtect=::CreateMutex(NULL,false,NULL);
 if(l_hmProtect==NULL)
 {
  cout<<"There is problem in creating the The mutex\n";
  return ;
 }
 while(g_iGoOn)
 {
  WaitForSingleObject(l_hmProtect,INFINITE);
              //this is the syncronized area
  (*a_iNum)++;
  g_iNum++;
 
  ReleaseMutex(l_hmProtect);

 }
}

 

 

void SyncWithSemaphore(int * a_iNum)
{
 static HANDLE l_hsProtect=CreateSemaphore(NULL,1,1,NULL);
 if(l_hsProtect==NULL)
 {
  cout<<"There is problem in creating the semaphore\n";
  return ;
 }


 while(g_iGoOn)
 {
  WaitForSingleObject(l_hsProtect,INFINITE);
  (*a_iNum)++;
  g_iNum++;
  ReleaseSemaphore(l_hsProtect,1,NULL);
 }

}

void main()
{

 typedef void (*TFunction)(int *);   //typedef for pointer to function

 TFunction func;

 int l_iChoice;


 cout<<"Choose 1, 2, 3, 4\n";
 cout<<"1 for not sync option\n";
 cout<<"2 for sync option with InterLocked Increment\n";
 cout<<"3 for sync with Mutex\n";
 cout<<"4 to sync with semaphore\n";
 cin>>l_iChoice;
 switch(l_iChoice)
 {
 case 1:  func=NotSyncThread;
  break;
 case 2:  func=Sync1;
  break;
 case 3:  func=SyncWithMutex;
  break;
 case 4:  func=SyncWithSemaphore;
  break;
 default:cout<<"The number is invalid exit the program\n";
  return;
 
 }
 
 
 int l_iNum1=0;
 int l_iNum2=0;


 HANDLE l_htThread1 = ::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)func,&l_iNum1,0,0);

 if(l_htThread1==NULL)
 {
  cout<<"There is problem in creating the thread\n";
  return;
 }

 HANDLE l_htThread2=::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)func,&l_iNum2,0,0);

 if(l_htThread2==NULL)
 {
  cout<<"There is problem in creating the thread ( second thread ) \n";
  return ;
 }

 

 

 

 ::MessageBox(NULL,"PressOkToStopTheThreads","Press Ok",0);
 
 g_iGoOn=0;  //Stop the thread functionality.


 cout<<"Number of iterations that run is "<<l_iNum1<<"+"<<l_iNum2<<"="<<l_iNum1+l_iNum2<<"\n";
 cout<<"The value of the global number is "<<g_iNum<<"\n";


 ::CloseHandle(l_htThread1);
 ::CloseHandle(l_htThread2);
 

}

//end the copy past marking.

Of course that there are alot of other protocols that can solv this thing, The most thing that is important to me when
I show this is that the user will expirience this problem in reality and not in theory.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

EyalHanan

Web Developer

Israel Israel

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralYou should read this first before submitting an article. PinmemberWREY12:30 8 Mar '04  
GeneralRe: You should read this first before submitting an article. Pinmembercristitomi10:50 4 Oct '07  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120517.1 | Last Updated 7 Mar 2004
Article Copyright 2004 by EyalHanan
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid