Download source code for this project here Thread Synchronization Using Mutex
The word mutex comes from mutually and exclusive. Mutexe is used to gain exclusive access to a resource mutually shared by two or more threads. Unlike critical sections, mutexes can be used to synchronize threads running in the same process or in different processes. There is one more difference between the two. If a thread locks a critical section and terminates without unlocking it, other threads waiting for the critical section to become free will be blocked indefinitely. However, if a thread that locks a mutex fails to unlock it before terminating, the system automatically frees the mutex so that waiting threads can resume. To synchronize threads within a process critical sections are preferred since critical sections are faster than mutexes.
MFC provides a class CMutex to permit thread synchronisation. Let us now see how to put this class to use. Suppose there is a file resource which we wish to share across two threads belonging to two different processes. One thread opens the file, sorts its contents, writes the sorted contents back to the file and finally closes it. The other thread opens the same file and displays its contents in an edit box. If one of the threads is in progress the other should get blocked. This synchronization is accomplished using the CMutex class. Let us now see how to achieve this programmatically.
Build an SDI application ‘mutex1’ without Doc/View support. Delete all the existing menu items and then add an item ‘Sort’ (having ID IDC_SORT) to it. #include ‘Afxmt.h’ file in ‘MainFrm.cpp’ file to make the CMutex class available. Add a global variable mutex of type CMutex *. Modify the constructor of CMainFrame class as shown below:
CMainFrame::CMainFrame( )
{
mutex = new CMutex ( FALSE, “filemutex” ) ;
}
Here we are creating a CMutex object. The first parameter passed to the CMutex constructor specifies whether the mutex is initially locked (TRUE) or unlocked (FALSE). The second parameter specifies the mutex’s name, which is used to synchronize threads in two different processes. Both processes must specify the same name so that the two CMutex objects will reference thesame mutex object in the Windows kernel.
Add a menu handler OnSort( ) for the ‘Sort’ menu item. Write the following code in it.
void CMainFrame::OnSort( )
{
AfxBeginThread ( sortthread, NULL ) ;
}
Here, we have started the thread by calling AfxBeginThread( ) function. Declare the thread function in ‘MainFrm.cpp’ as given below:
UINT sortthread ( LPVOID param ) ;
Write the thread function sortthread as given below:
UINT sortthread ( LPVOID param ) ;
{
mutex -> Lock( ) ;
CString str[300], temp ;
CStdioFile f ;
if ( f.Open ( “c:\\text.txt”, CFile::modeReadWrite ) == 0 )
{
AfxMessageBox ( “Cannot open file” ) ;
return TRUE ;
}
int count = 0 ;
while ( f.ReadString ( str[count] ) )
count++ ;
for ( int j = 0 ; j < count – 1 ; j++ )
{
for ( int k = j + 1 ; k < count ; k++ )
{
if ( str[j] > str[k] )
{
temp = str[j] ;
str[j] = str[k] ;
str[k] = temp ;
}
}
}
f.SeekToBegin( ) ;
for ( int i = 0 ; i < count ; i++ )
{
f.WriteString ( str[i] ) ;
f.WriteString ( “\n” ) ;
}
f.Close( ) ;
mutex -> Unlock( ) ;
return 0 ;
}
Here, we have locked the mutex by calling CMutex::Lock( ). Next, we have opened the file, sorted its contents and written the sorted contents back to the file. Thereafter, we have unlocked the mutex using CMutex::Unlock( ) function.
By default, Lock( ) will wait forever for a mutex to become unlocked. Alternatively, we can specify a maximum wait time in milliseconds. In such case if Lock( ) returns 0, it means that time out period expired first, and if it returns a non-zero value it means that the mutex came free.
Now create another SDI application ‘mutex2’ without Doc/View support. Delete all the existing menu items and then add a menu ‘Read’ having ID IDC_READ. #include ‘Afxmt.h’ file in ‘MainFrm.cpp’ file. Add global variables mutex of type CMutex* and edit of type CEdit.
In the constructor of CMainFrame class write the following statement:
CMainFrame::CMainFrame( )
{
mutex = new CMutex ( FALSE, “filemutex” ) ;
}
Note that the second parameter passed to the constructor is same as one we have passed while creating CMutex’s object in ‘mutex1’ application.
Modify CMainFrame::OnCreate( ) as shown below:
int CMainFrame::OnCreate ( LPCREATESTRUCT lpCreateStruct )
{
// Code added by AppWizard
edit.Create ( WS_CHILD | WS_VISIBLE | ES_MULTILINE, rectDefault, this,
AFX_IDW_PANE_FIRST ) ;.
return 0 ;
}
In this function, we have created an edit box where the contents of the file will be displayed.
Add a menu handler OnRead( ) for the ‘Read’ menu item. Write the following code in it.
void CMainFrame::OnRead( )
{
AfxBeginThread ( readthread, NULL ) ;
}
Here, we have started a thread readthread which is given below:
UINT readthread ( LPVOID param )
{
mutex -> Lock( ) ;
CString str, editstr ;
CStdioFile f ;
if ( f.Open ( “c:\\text.txt”, CFile::modeReadWrite ) == 0 )
{
AfxMessageBox ( “Cannot open file” ) ;
return TRUE ;
}
while ( f.ReadString ( str ) )
editstr += str ;
edit.SetWindowText ( editstr ) ;
f.Close( ) ;
mutex -> Unlock( ) ;
return 0 ;
}
Declare the thread function in ‘MainFrm.cpp’ as
UINT readthread ( LPVOID param ) ;
Here, again we have locked the mutex, read the file and displayed the contents in the edit box by calling CWnd::SetWindowText( ) function.
Create a file ‘text.txt’ in ‘C:\’. The file must be big enough so that sorting will take more than a couple of seconds. Run both the applications. Click the ‘Sort’ menu from one application and immediately click the ‘Read’ menu from the other. The thread that reads the file waits until sorting completes and then displays the contents. On the other hand had we not synchronized the threads and tried to read the file while sorting is in progress a message box would have popped up reporting an error ‘Cannot open file’.
Download source code for this project here Thread Synchronization Using Mutex