C++ 线程同步之临界区CRITICAL_SECTION

一、临界区

临界区又称关键代码段,指的是一小段代码在代码执行前,他需要独占一些资源。程序中通常将多线程同时访问的某个资源作为临界区,需要定义一个CRITICAL_SECTION类型的变量,然后调用InitializeCriticalSection函数对变量进行初始化;

函数声明:

VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection );

lpCriticalSection:一个CRITICAL_SECTION结构指针,表示用于初始化的临界区;

InitializeCriticalSection函数在内部设置了CRITICAL_SECTION结构的某些成员变量,所以他不会失败。

为了将某一段代码定义为临界区,需要调用EnterCriticalSection函数;

VOID WINAPI EnterCriticalSection(__inout LPCRITICAL_SECTION lpCriticalSection);

该函数的作用是判断是否有线程访问临界区资源,如果没有,就改变CRITICAL_SECTION结构的成员变量的值,赋予当前线程访问权,函数立即返回;如果有线程正在访问资源,则进入等待状态,直到没有线程访问。

释放资源函数:

void WINAPI LeaveCriticalSection( _Inout_LPCRITICAL_SECTION lpCriticalSection);

释放CRITICAL_SECTION结构指针

void WINAPI DeleteCriticalSection(_Inout_ LPCRITICAL_SECTION lpCriticalSection);

二、学习案例

用三个线程同时运行将一个变量增加到30;

临界区对象类

#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();如果是用的时候只定义锁对象,可以不手动进入临界区和退出临界区
}

CAutoLock::~CAutoLock()
{
	DeleteCriticalSection(&m_Section);
	//UnLock();
}

void CAutoLock::Lock()
{
	EnterCriticalSection(&m_Section);
}

void CAutoLock::UnLock()
{
	LeaveCriticalSection(&m_Section);
}

三个线程创建类

#ifndef _TEST_CRITICAL_SECTION_H__
#define _TEST_CRITICAL_SECTION_H__
#include "CAutoLock.h"
class TestCriticalSection
{
public:
	TestCriticalSection();
	~TestCriticalSection();

	void StartThread();//开始线程函数

	
	static DWORD __stdcall ThreadFun1(LPVOID lParam);//线程回调函数1
	static DWORD __stdcall ThreadFun2(LPVOID lParam);//线程回调函数2
	static DWORD __stdcall ThreadFun3(LPVOID lParam);//线程回调函数3

private:
	HANDLE m_hThread1;
        HANDLE m_hThread2;
	HANDLE m_hThread3;

	CAutoLock m_lock;//三个线程公用的临界区锁

	static int m_nTotals;
};

#endif
#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只需要加在类定义里,类定义外面的函数定义前不能写static
{
	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;
		
		if (pThis->m_nTotals >= 30)
		{
			break;
		}
                pThis->m_lock.UnLock();
		Sleep(10);
	}

	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;
		
		if (pThis->m_nTotals >= 30)
		{
			break;
		}
                pThis->m_lock.UnLock();
		Sleep(10);
	}
	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;
		
		if (pThis->m_nTotals >= 30)
		{
			break;
		}
                pThis->m_lock.UnLock();
		Sleep(10);
	}

	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);
}

主函数:

// CriticalSection.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "CCriticalSection.h"

int _tmain(int argc, _TCHAR* argv[])
{
	TestCriticalSection  CriticalSectionObj;
	CriticalSectionObj.StartThread();
	Sleep(5000);
	system("pause");
	return 0;
}

结果:

 

如果代码改成下面这样,不加临界区;资源访问会冲突

#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只需要加在类定义里,类定义外面的函数定义前不能写static
{
	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);
}

结果可能会出现下面这种状况

 

 

 

 

 

  • 9
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
c builder线程临界区critical section)指的是在并发编程中,多个线程同时操作共享的数据时,需要保证某些代码段在同一时刻只能由一个线程执行,否则可能会产生竞态条件(race condition)。在c builder中,通过使用锁机制(包括互斥锁、读写锁、信号量等)来实现线程临界区的保护。 临界区的设置需要考虑多个方面,例如:哪些代码段需要保护、保护的临界区是否越小越好、保护的代价是否过高等。一般来说,临界区应尽量小,以减少锁的持有时间,提高并发效率;同时,需要注意临界区的合理设置,以防止死锁等并发编程常见问题的发生。 在c builder中,通过使用相关锁机制实现线程临界区的保护,例如: - 使用互斥锁(TMutex):在一个线程进入临界区时获取互斥锁并加锁,其他线程需要等待锁被释放后才能进入,执行完临界区代码后释放锁。 - 使用读写锁(TMultiReadExclusiveWriteSynchronizer):在读操作时多个线程可以同时访问临界区,但在写操作时只能有一个线程操作,其他线程需要等待。可以提高读操作的并发性能。 - 使用信号量(TSemaphore):通过设置可访问的线程数目,限定同时可以访问临界区的线程数量,保证对共享数据的顺序和正确性。 综上所述,对于c builder中的线程临界区,需要根据具体的场景选择合适的锁机制来进行保护,以确保共享数据的正确性和并发性能的提高。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值