1. Critical area
A critical section, also known as a critical code segment, refers to a small piece of code that needs to monopolize some resources before the code is executed . In the program, a resource accessed by multiple threads at the same time is usually used as a critical section. It is necessary to define a variable of type CRITICAL_SECTION , and then call the InitializeCriticalSection function to initialize the variable;
Function declaration:
VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection );
lpCriticalSection: a pointer to a CRITICAL_SECTION structure representing the critical section used for initialization;
The InitializeCriticalSection function internally sets some member variables of the CRITICAL_SECTION structure, so it will not fail.
In order to define a section of code as a critical section, you need to call the EnterCriticalSection function;
VOID WINAPI EnterCriticalSection(__inout LPCRITICAL_SECTION lpCriticalSection);
The function of this function is to judge whether there is a thread accessing the resource in the critical section. If not, change the value of the member variable of the CRITICAL_SECTION structure, give the current thread access right, and the function returns immediately; if a thread is accessing the resource, it will enter the waiting state until No thread access.
Release resource function:
void WINAPI LeaveCriticalSection( _Inout_LPCRITICAL_SECTION lpCriticalSection);
Free the CRITICAL_SECTION structure pointer
void WINAPI DeleteCriticalSection(_Inout_ LPCRITICAL_SECTION lpCriticalSection);
The case study
Increase a variable to 30 with three threads running simultaneously;
critical section object class
#ifndef CAUTO_LOCK_H__ #define CAUTO_LOCK_H__ class CAutoLock { public: CAutoLock(); ~CAutoLock(); void Lock(); void UnLock(); private: CRITICAL_SECTION m_Section; }; #endif
#include "stdafx.h" #include "CAutoLock.h" CAutoLock::CAutoLock() { InitializeCriticalSection(&m_Section); //Lock(); If only the lock object is defined when it is used, it is not necessary to manually enter and exit the critical area } CAutoLock::~CAutoLock() { DeleteCriticalSection(&m_Section); //UnLock(); } void CAutoLock::Lock() { EnterCriticalSection(&m_Section); } void CAutoLock::UnLock() { LeaveCriticalSection(&m_Section); }
Three thread creation classes
#ifndef _TEST_CRITICAL_SECTION_H__ #define _TEST_CRITICAL_SECTION_H__ #include "CAutoLock.h" class TestCriticalSection { public: TestCriticalSection(); ~TestCriticalSection(); void StartThread();//Start thread function static DWORD __stdcall ThreadFun1(LPVOID lParam);//Thread callback function 1 static DWORD __stdcall ThreadFun2(LPVOID lParam);//Thread callback function 2 static DWORD __stdcall ThreadFun3(LPVOID lParam);//Thread callback function 3 private: HANDLE m_hThread1; HANDLE m_hThread2; HANDLE m_hThread3; CAutoLock m_lock;//Critical section lock common to three threads static int m_nTotals; }; #endif
#include "stdafx.h" #include "CCriticalSection.h" #include <iostream> using namespace std; int TestCriticalSection::m_nTotals = 0;//Initialize static member variables TestCriticalSection::TestCriticalSection() { m_nTotals = 0; m_hThread1 = INVALID_HANDLE_VALUE; m_hThread2 = INVALID_HANDLE_VALUE; } TestCriticalSection::~TestCriticalSection() { if (m_hThread1 != NULL) { CloseHandle(m_hThread1); m_hThread1 = NULL; } if (m_hThread2 != NULL) { CloseHandle(m_hThread2); m_hThread2 = NULL; } if (m_hThread3 != NULL) { CloseHandle(m_hThread3); m_hThread3 = NULL; } } DWORD __stdcall TestCriticalSection::ThreadFun1(LPVOID lParam) //static only needs to be added to the class definition, static cannot be written before the function definition outside the class definition { DWORD dRet = TRUE; TestCriticalSection * pThis = static_cast<TestCriticalSection*>(lParam); while(1) { pThis->m_lock.Lock(); pThis->m_nTotals ++; cout<<"ThreadFun1: m_nTotals "<<pThis->m_nTotals<<endl; pThis->m_lock.UnLock(); Sleep(10); if (pThis->m_nTotals == 30) { break; } } return dRet; } DWORD __stdcall TestCriticalSection::ThreadFun2(LPVOID lParam) { DWORD dRet = TRUE; TestCriticalSection * pThis = static_cast<TestCriticalSection*>(lParam); while(1) { pThis->m_lock.Lock(); pThis->m_nTotals ++; cout<<"ThreadFun2: m_nTotals "<<pThis->m_nTotals<<endl; pThis->m_lock.UnLock(); Sleep(10); if (pThis->m_nTotals == 30) { break; } } return dRet; } DWORD __stdcall TestCriticalSection::ThreadFun3(LPVOID lParam) { DWORD dRet = TRUE; TestCriticalSection * pThis = static_cast<TestCriticalSection*>(lParam); while(1) { pThis->m_lock.Lock(); pThis->m_nTotals ++; cout<<"ThreadFun3: m_nTotals "<<pThis->m_nTotals<<endl; pThis->m_lock.UnLock(); Sleep(10); if (pThis->m_nTotals == 30) { break; } } return dRet; } void TestCriticalSection::StartThread() { m_hThread1 = CreateThread(NULL, 0, &TestCriticalSection::ThreadFun1, this, 0, NULL); m_hThread2 = CreateThread(NULL, 0, &TestCriticalSection::ThreadFun2, this, 0, NULL); m_hThread3 = CreateThread(NULL, 0, &TestCriticalSection::ThreadFun3, this, 0, NULL); }
Main function:
// CriticalSection.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "CCriticalSection.h" int _tmain(int argc, _TCHAR* argv[]) { TestCriticalSection CriticalSectionObj; CriticalSectionObj.StartThread(); Sleep(5000); system("pause"); return 0; }
result:
If the code is changed to the following, no critical section is added; resource access will conflict
#include "stdafx.h" #include "CCriticalSection.h" #include <iostream> using namespace std; int TestCriticalSection::m_nTotals = 0; TestCriticalSection::TestCriticalSection() { m_nTotals = 0; m_hThread1 = INVALID_HANDLE_VALUE; m_hThread2 = INVALID_HANDLE_VALUE; } TestCriticalSection::~TestCriticalSection() { if (m_hThread1 != NULL) { CloseHandle(m_hThread1); m_hThread1 = NULL; } if (m_hThread2 != NULL) { CloseHandle(m_hThread2); m_hThread2 = NULL; } if (m_hThread3 != NULL) { CloseHandle(m_hThread3); m_hThread3 = NULL; } } DWORD __stdcall TestCriticalSection::ThreadFun1(LPVOID lParam) //static only needs to be added to the class definition, static cannot be written before the function definition outside the class definition { DWORD dRet = TRUE; TestCriticalSection * pThis = static_cast<TestCriticalSection*>(lParam); while(1) { //pThis->m_lock.Lock(); pThis->m_nTotals ++; cout<<"ThreadFun1: m_nTotals "<<pThis->m_nTotals<<endl; //pThis->m_lock.UnLock(); Sleep(10); if (pThis->m_nTotals == 30) { break; } } return dRet; } DWORD __stdcall TestCriticalSection::ThreadFun2(LPVOID lParam) { DWORD dRet = TRUE; TestCriticalSection * pThis = static_cast<TestCriticalSection*>(lParam); while(1) { //pThis->m_lock.Lock(); pThis->m_nTotals ++; cout<<"ThreadFun2: m_nTotals "<<pThis->m_nTotals<<endl; //pThis->m_lock.UnLock(); Sleep(10); if (pThis->m_nTotals == 30) { break; } } return dRet; } DWORD __stdcall TestCriticalSection::ThreadFun3(LPVOID lParam) { DWORD dRet = TRUE; TestCriticalSection * pThis = static_cast<TestCriticalSection*>(lParam); while(1) { //pThis->m_lock.Lock(); pThis->m_nTotals ++; cout<<"ThreadFun3: m_nTotals "<<pThis->m_nTotals<<endl; //pThis->m_lock.UnLock(); Sleep(10); if (pThis->m_nTotals == 30) { break; } } return dRet; } void TestCriticalSection::StartThread() { m_hThread1 = CreateThread(NULL, 0, &TestCriticalSection::ThreadFun1, this, 0, NULL); m_hThread2 = CreateThread(NULL, 0, &TestCriticalSection::ThreadFun2, this, 0, NULL); m_hThread3 = CreateThread(NULL, 0, &TestCriticalSection::ThreadFun3, this, 0, NULL); }
As a result, the following situations may occur