Deadlock and Critical Section Program Example
The following program example uses critical section to demonstrate the deadlock situation. Keep in mind that other synchronization objects also will demonstrates the deadlock situation if not used properly.
Create a new empty Win32 console application project. Give a suitable project name and change the project location if needed.
Then, add the source file and give it a suitable name.
Next, add the following source code.
#include <windows.h>
#include <stdio.h>
// Global variable
CRITICAL_SECTION csA, csB;
LONG WINAPI ThreadFunc(LONG);
int wmain(void)
{
HANDLE hThread;
DWORD dwThreadID;
wprintf(LThe current process ID is %u\n, GetCurrentProcessId());
// The main thread, Thread1...
wprintf(LThe current thread ID is %u\n, GetCurrentThreadId());
wprintf(L\n);
// Initializes a critical section objects
// This function does not return a value
InitializeCriticalSection(&csA);
InitializeCriticalSection(&csB);
// Creates a thread to execute within the virtual address space of the calling process (main()).
hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFunc,NULL,0,&dwThreadID);
if(hThread != NULL)
wprintf(LCreateThread() is OK, thread ID is %u\n, dwThreadID);
else
wprintf(LCreateThread() failed, error %u\n, GetLastError());
// Closes the open thread handle.
if(CloseHandle(hThread) != 0)
wprintf(LhThread handle was successfully closed!\n);
else
wprintf(LFailed to close hThread handle, error %u\n, GetLastError());
wprintf(L\n);
// While true...
while(1)
{
// 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(&csA);
wprintf(LThread1 (%u) has entered Critical Section A but not B.\n, GetCurrentThreadId());
EnterCriticalSection(&csB);
wprintf(LThread1 (%u) has entered Critical Section A and B!\n, GetCurrentThreadId());
// Releases ownership of the specified critical section object.
// This function does not return a value.
LeaveCriticalSection(&csB);
wprintf(LThread1 (%u) has left Critical Section B but still owns A.\n, GetCurrentThreadId());
LeaveCriticalSection(&csA);
wprintf(LThread1 (%u) has left both critical sections, A and B...\n, GetCurrentThreadId());
Sleep(50);
};
return 0;
}
LONG WINAPI ThreadFunc(LONG lParam)
{
// The child thread, Thread2...
// While true
while(1)
{
EnterCriticalSection(&csB);
wprintf(LThread2 (%u) has entered Critical Section B but not A.\n, GetCurrentThreadId());
EnterCriticalSection(&csA);
wprintf(LThread2 (%u) has entered Critical Section B and A!\n, GetCurrentThreadId());
LeaveCriticalSection(&csA);
wprintf(LThread2 (%u) has left Critical Section A but still owns B.\n, GetCurrentThreadId());
LeaveCriticalSection(&csB);
wprintf(LThread2 (%u) has left both critical sections, A and B...\n, GetCurrentThreadId());
Sleep(50);
};
}
Build and run the project. The following are the sample outputs.
We can use Windows Task Manager to verify the threads creation.
The following is another sample output.
Thread 1 has claimed critical section A and is suspended because it is waiting to enter critical section B, whereas Thread 2 owns critical section B and waits for Thread 1 to release critical section A, which will never happen, of course, because Thread 1 will not release critical section A before Thread 2 has released critical section B, which will never happen, of course and these processes repeat.