关键代码段,也称为临界区,工作在用户方式下。它是指一个小代码段,在代码能够执行前,它必须独占对某些资源的访问权。通常把多线程中访问同一种资源的那部分代码当做关键代码段。

1. 初始化关键代码段

调用InitializeCriticalSection函数初始化一个关键代码段。

InitializeCriticalSection(
    _Out_ LPCRITICAL_SECTION lpCriticalSection
    );

该函数只有一个指向CRITICAL_SECTION结构体的指针。在调用InitializeCriticalSection函数之前,首先需要构造一个CRITICAL_SCTION结构体类型的对象,然后将该对象的地址传递给InitializeCriticalSection函数。

2进入关键代码段

VOID
WINAPI
EnterCriticalSection(
    _Inout_ LPCRITICAL_SECTION lpCriticalSection
    );

调用EnterCriticalSection函数,以获得指定的临界区对象的所有权,该函数等待指定的临界区对象的所有权,如果该所有权赋予了调用线程,则该函数就返回;否则该函数会一直等待,从而导致线程等待。

3.退出关键代码段

VOID
WINAPI
LeaveCriticalSection(
    _Inout_ LPCRITICAL_SECTION lpCriticalSection);
线程使用完临界区所保护的资源之后,需要调用LeaveCriticalSection函数,释放指定的临界区对象的所有权。之后,其他想要获得该临界区对象所有权的线程就可以获得该所有权,从而进入关键代码段,访问保护的资源。

4.删除临界区

WINBASEAPI
VOID
WINAPI
DeleteCriticalSection(
    _Inout_ LPCRITICAL_SECTION lpCriticalSection
    );
当临界区不再需要时,可以调用DeleteCriticalSection函数释放该对象,该函数将释放一个没有被任何线程所拥有的临界区对象的所有资源。
BOOL COneIPCChannel::InitIPCChannel(CWnd * pVideoWnd)
{
	m_pVideoBuffer = new CVideoRecieveBuffer;
	m_pVideoWnd = pVideoWnd;
	m_bPlaying = FALSE;
	m_isTFPlay=FALSE;
	InitializeCriticalSection(&m_cs);
	m_hWaitEvent = CreateEvent(NULL,FALSE,FALSE,NULL);

	return TRUE;
}

BOOL COneIPCChannel::InitIPCChannelREMOTE(CWnd * pVideoWnd,int *Session)
{
	m_Session=Session;
	m_pVideoWnd = pVideoWnd;
	m_bPlaying = FALSE;
	m_isTFPlay = FALSE;
	m_pVideoBuffer = new CVideoRecieveBuffer;
	InitializeCriticalSection(&m_cs);
	m_hWaitEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
	return TRUE;
}

卖票系统

#include <stdio.h>
#include <windows.h>
#include <process.h> 


int iTickets = 5000;
CRITICAL_SECTION g_cs;

// A窗口     B窗口

DWORD WINAPI SellTicketA(void* lpParam)
{
	while (1)
	{
		EnterCriticalSection(&g_cs);//进入临界区
		if (iTickets > 0)
		{
			Sleep(1);
			iTickets--;
			printf("A remain %d\n", iTickets);
			LeaveCriticalSection(&g_cs);//离开临界区
		}
		else
		{
			LeaveCriticalSection(&g_cs);//离开临界区
			break;
		}
	}
	return 0;
}

DWORD WINAPI SellTicketB(void* lpParam)
{
	while (1)
	{
		EnterCriticalSection(&g_cs);//进入临界区
		if (iTickets > 0)
		{
			Sleep(1);
			iTickets--;
			printf("B remain %d\n", iTickets);
			LeaveCriticalSection(&g_cs);//离开临界区
		}
		else
		{
			LeaveCriticalSection(&g_cs);//离开临界区
			break;
		}
	}
	return 0;
}


int main()
{
	HANDLE hThreadA, hThreadB;
	hThreadA = CreateThread(NULL, 0, SellTicketA, NULL, 0, NULL);  //2
	hThreadB = CreateThread(NULL, 0, SellTicketB, NULL, 0, NULL);  //2
	CloseHandle(hThreadA); //1
	CloseHandle(hThreadB); //1
	InitializeCriticalSection(&g_cs); //初始化关键代码段
	Sleep(40000);
	DeleteCriticalSection(&g_cs);//删除临界区
	system("pause");

	return 0;
}