Windows Thread Synchronization 44

 

 

 

 

 

Synchronization with Critical Sections Program Example

 

Another mechanism for solving this simple scenario is to use a critical section. A critical section is similar to InterlockedExchange except that you have the ability to define the logic that takes place as an atomic operation. Critical section objects provide synchronization similar to that provided by mutex objects, except that critical section objects can be used only by the threads of a single process. Critical section objects provide a slightly faster, more efficient mechanism for mutual-exclusion synchronization (a processor-specific test and set instruction) as compared to event, mutex, and semaphore objects, which can also be used in a single-process application. There is no guarantee about the order in which threads will obtain ownership of the critical section; however, the system will be fair to all threads. Unlike a mutex object, there is no way to tell whether a critical section has been abandoned. The process is responsible for allocating the memory used by a critical section. Typically, this is done by just declaring a variable of type CRITICAL_SECTION. Before the threads of the process can use it, initialize the critical section and then request ownership of a critical section. If the critical section object is currently owned by another thread, the process waits indefinitely for ownership. In contrast, when a mutex object is used for mutual exclusion, the wait functions accept a specified time-out interval. The TryEnterCriticalSection function attempts to enter a critical section without blocking the calling thread.

A thread uses the InitializeCriticalSectionAndSpinCount or SetCriticalSectionSpinCount functions to specify a spin count for the critical section object. On single-processor systems, the spin count is ignored and the critical section spin count is set to 0. On multiprocessor systems, if the critical section is unavailable, the calling thread will spin dwSpinCount times before performing a wait operation on a semaphore associated with the critical section. If the critical section becomes free during the spin operation, the calling thread avoids the wait operation. Any thread of the process can release the system resources that were allocated when the critical section object was initialized. After this function has been called, the critical section object can no longer be used for synchronization.

Create a new empty Win32 console application project. Give a suitable project name and change the project location if needed.

 

Synchronization with Critical Sections Program Example: Creating new C++ Win32 console application project

 

Then, add the source file and give it a suitable name.

 

Synchronization with Critical Sections Program Example: Adding new C++ source file

 

Next, add the following source code.

 

#include <Windows.h>

#include <stdio.h>

 

// Shared global variables

CRITICAL_SECTION g_cs;

WCHAR message[] = L"Hello I'm new Thread";

 

DWORD WINAPI thread_function(LPVOID arg)

{

      int count2;

     

      wprintf(L"thread_function() is running. Argument received was: %s\n", arg);

      wprintf(L"Child thread entering critical section, doing job & leaving critical section...\n");

      wprintf(L"\n");

 

      for (count2 = 0; count2 < 10; count2++)

      {

            // Waits for ownership of the specified critical section object.

            // The function returns when the calling thread is granted ownership.

            // This function does not return a value.

            EnterCriticalSection(&g_cs);

            wprintf(L"Y ");

            // Releases ownership of the specified critical section object.

            // This function does not return a value.

            LeaveCriticalSection(&g_cs);

      }

      Sleep(4000);

      return 0;

}

 

int wmain()

{

      HANDLE a_thread;

      DWORD a_threadId;

      DWORD thread_result;

      int count1;

 

      // Some info

      wprintf(L"The current process ID is %u\n", GetCurrentProcessId());

      wprintf(L"The main thread ID is %u\n", GetCurrentThreadId());

      wprintf(L"\n");

     

      // Initializes a critical section object.

      // This function does not return a value.

      InitializeCriticalSection(&g_cs);

 

      // Create a new thread.

      a_thread = CreateThread(NULL, 0, thread_function, (LPVOID)message, 0, &a_threadId);

 

      if (a_thread == NULL)

      {

            wprintf(L"CreateThread() - Thread creation failed, error %u\n", GetLastError());

            exit(EXIT_FAILURE);

      }

      else

            wprintf(L"CreateThread() is OK, thread ID is %u\n", a_threadId);

 

      wprintf(L"main() thread entering critical section, doing job & leaving critical section...\n");

      wprintf(L"Entering main() loop...\n");

 

      for (count1 = 0; count1 < 10; count1++)

      {

            EnterCriticalSection(&g_cs);

            wprintf(L" X");

            LeaveCriticalSection(&g_cs);

      }

     

      Sleep(3000);

      wprintf(L"\n\nWaiting for thread %u to finish...\n", a_threadId);

 

      if (WaitForSingleObject(a_thread, INFINITE) != WAIT_OBJECT_0)

      {

            wprintf(L"WaitForSingleObject() - Thread join failed, error %u", GetLastError());

            exit(EXIT_FAILURE);

      }

      else

            wprintf(L"WaitForSingleObject() is OK! An object was signaled\n");

     

            // Retrieve the code returned by the thread.

      if(GetExitCodeThread(a_thread, &thread_result) != 0)

            wprintf(L"GetExitCodeThread() is OK! Thread joined, exit code %u\n", thread_result);

      else

            wprintf(L"GetExitCodeThread() failed, error %u\n", GetLastError());

 

      if(CloseHandle(a_thread) != 0)

            wprintf(L"a_thread handle was closed successfully!\n");

      else

            wprintf(L"Failed to close a_thread handle, error %u\n", GetLastError());

     

      // Releases all resources used by an unowned critical section object.

      // This function does not return a value.

      wprintf(L"Deleting critical section resources...\n");

      DeleteCriticalSection(&g_cs);

 

      exit(EXIT_SUCCESS);

}

 

Build and run the project. The following are the sample outputs when the program was run many times.

 

Synchronization with Critical Sections Program Example: A sample program output

 

Synchronization with Critical Sections Program Example: Another sample program output

 

Synchronization with Critical Sections Program Example: More sample program output

 

 

 

 

< Thread Synchronization 43 | Thread Synchronization Programming | Win32 Programming | Thread Synchronization 45 >