|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionIn my previous article, we discussed simple multithreaded programming in C, Win32 and MFC. Now, we see simple thread synchronization with Win32 API and MFC. What is Thread Synchronization?In a multithreaded environment, each thread has its own local thread stack and registers. If multiple threads access the same resource for read and write, the value may not be the correct value. For example, let's say our application contains two threads, one thread for reading content from the file and another thread writing the content to the file. If the write thread tries to write and the read thread tries to read the same data, the data might become corrupted. In this situation, we want to lock the file access. The thread synchronization has two stages. Signaled and non-signaled. The signaled state allows objects to access and modify data. The non-signaled state does allow accessing or modifying the data in the thread local stack. Thread Synchronization methods:Many of the thread synchronization methods are used to synchronize multiple threads. The following methods are used to synchronize between objects. Thread Synchronization on different processes:Event:Event is a thread synchronization object used to set the signaled or non-signaled state. The signaled state may be manual or automatic depending on the event declaration. Mutex:Mutex is the thread synchronization object which allows to access the resource only one thread at a time. Only when a process goes to the signaled state are the other resources allowed to access. Semaphore:Semaphore is a thread synchronization object that allows zero to any number of threads access simultaneously. Thread Synchronization in same process:Critical SectionThe critical section is a thread synchronization object. The other synchronization objects like semaphore, event, and mutex are used to synchronize the resource with different processes. But, the critical section allows synchronization within the same process. The given difference is the main difference between the thread synchronization objects. The other differences between the thread synchronization are the following: Win32 Wait Functions:The Wait family of functions are used to wait the thread synchronization object while a process completes. The widely used functions are The MFC Lock/Unlock Resource:The MFC The The The Thread Synchronization Objects:Critical Section:The Critical section object is same as the Mutex object. But, the Mutex object allows synchronizing objects across the process. But the Critical section object does not allow synchronization with different processes. The critical section is used to synchronize the threads within the process boundary. It is possible to use Mutex instead of critical section. But, the critical section thread synchronization object is slightly faster compared to other synchronization objects. The critical section object synchronizes threads within the process. Critical section allows accessing only one thread at a time. Win32 Critical Section Object:The process allocates memory for the critical section using the typedef struct _RTL_CRITICAL_SECTION { PRTL_CRITICAL_SECTION_DEBUG DebugInfo; // The following three fields control entering // and exiting the critical section for the resource LONG LockCount; LONG RecursionCount; HANDLE OwningThread; // from the thread's ClientId->UniqueThread HANDLE LockSemaphore; DWORD SpinCount; } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION; In critical section, we allocate memory for If any of the other synchronization object names is same as Critical section object, the Critical section object waits for the ownership infinitely. The Critical section object does not allow moving or copying the object. If we have to synchronize the thread on different processes, use Mutex object. Example:CRITICAL_SECTION m_cs; //Initilize the critical section InitializeCriticalSection(&m_cs); The two threads try to access the same variable. The global variable UINT ThreadOne(LPVOID lParam)
{
//
// Lock the Critical section
EnterCriticalSection(&m_cs);
// Some Process
//Release the Critical section
LeaveCriticalSection(&m_cs);
return 0;
}
Thread two: UINT ThreadTwo(LPVOID lParam)
{
// Lock the Critical section
EnterCriticalSection(&m_cs);
// Some Process
//Release the Critical section
LeaveCriticalSection(&m_cs);
// return the thread
return 0;
}
MFC Critical Section object:The The Example:// Global Critical section CCriticalSection c_s; int g_C; //////////////////Thread One /////////////////////// UINT ThreadFunction1(LPVOID lParam) { // Create object for Single Lock CSingleLock lock(&c_s); // Lock lock.Lock(); // Process // Unlock lock.Unlock(); // return return 0; } ////////////Thraed 2//////////////////// UINT ThreadFunction2(LPVOID lParam) { // Single Lock Constract Critical Section CSingleLock lock(&c_s); // Lock lock.Lock(); // Process // Unlock lock.Unlock(); //return return 0; } Event:Event is the thread synchronization object to set signaled state or non-signaled state. The Event has two types. They are manual reset event and auto reset event. The manual event has signaled user set to non-signaled state, uses Win32 Event Object:The
Example:// Handle for Event HANDLE g_Event; // Create a manual-reset event object with no security attributes g_Event = CreateEvent( NULL, TRUE, TRUE, "Event" ); ResetEvent(g_Event); // Do Process SetEvent(g_Event); MFC Event Object:Event is useful for waiting if something happens (or an event occurs). MFC The Manual event object signaled/non-signaled uses Mutex Synchronization Object:Mutex is the synchronization object used to synchronize the threads with more than one process. The Mutex is as the name tells, mutually exclusive. The Mutex object allows accessing the resource single thread at a time. Win32 Mutex Object:The If we create two-named Mutex using The ExampleHANDLE g_Mutex; DWORD dwWaitResult; // Create a mutex with initial owner. g_Mutex = CreateMutex( NULL, TRUE, "MutexToProtectDatabase"); // Wait for ownership dwWaitResult = WaitForSingleObject( g_Mutex, 5000L); // Check takes ownership // Release Mutex ReleaseMutex(g_Mutex)) MFC Mutex Object:The MFC To control resource access for single Mutex object, use // Global Mutex Object CMutex g_m; int g_C; UINT ThreadFunction1(LPVOID lParam) { // Create object for Single Lock CSingleLock lock(&g_m); lock.Lock(); // Process lock.Unlock(); // return return 0; } UINT ThreadFunction2(LPVOID lParam) { // Single Lock Construct Mutex CSingleLock lock(&g_m); lock.Lock(); // Process lock.Unlock(); //return return 0; } Semaphore Thread Synchronization Object:Semaphore is a thread synchronization object that allows accessing the resource for a count between zero and maximum number of threads. If the Thread enters the semaphore, the count is incremented. If the thread completed the work and is removed from the thread queue, the count is decremented. When the thread count goes to zero, the synchronization object is non-signaled. Otherwise, the thread is signaled. Win32 Semaphore Synchronization Object:The The Example:HANDLE g_Semaphore; // Create a semaphore with initial and max. g_Semaphore = CreateSemaphore( NULL, 4, 4, NULL); DWORD dwWaitResult; //take ownership dwWaitResult = WaitForSingleObject( g_Semaphore, 0L); // Check the ownership // Release Semaphore ReleaseSemaphore( g_Semaphore, 1, NULL) ; MFC Semaphore Synchronization Object:The The virtual destructor is used to delete the Conclusion:Thread Synchronization is used to access the shared resources in a multithread environment. The programmer decides the situation for when to use the synchronization object efficiently. The MFC Thread Synchronization classes internally call the Win32 API functions. The MFC Thread Synchronization classes wrap many of the functionalities form the Windows environment.
|
||||||||||||||||||||||