关键段CRITICAL_SECTION 与 互斥量Mutex 在线程互斥的性能比较

本文探讨了在多线程环境中,互斥量与临界区锁的使用及性能对比。通过具体测试代码,展示了两种锁类型在资源访问控制中的效率差异,并指出临界区锁在同进程多线程中效率更高。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在多线程环境,对资源进行访问的时候,一般都需要加锁。这时候就涉及到加锁的性能问题:

lock.h

#ifndef _LOCK_H_
#define _LOCK_H_
#include <windows.h>


//锁接口类
class ILock
{
public:
	virtual ~ILock() {}

	virtual void Lock() const = 0;
	virtual void Unlock() const = 0;
};


//互斥对象锁类
class CMutex : public ILock
{
public:
	CMutex();
	~CMutex();

	virtual void Lock() const;
	virtual void Unlock() const;

private:
	HANDLE m_mutex;
};


//临界区锁类
class CriSection : public ILock
{
public:
	CriSection();
	~CriSection();

	virtual void Lock() const;
	virtual void Unlock() const;

private:
	CRITICAL_SECTION m_critclSection;
};


//自动锁
class CAutoLock
{
public:
	CAutoLock(const ILock&);
	~CAutoLock();

private:
	const ILock& m_lock;
};


#endif

lock.cpp

#include "StdAfx.h"
#include "Lock.h"


//创建一个匿名互斥对象
CMutex::CMutex()
{
	m_mutex = ::CreateMutex(NULL, FALSE, NULL);
}

//销毁互斥对象,释放资源
CMutex::~CMutex()
{
	::CloseHandle(m_mutex);
}

//确保拥有互斥对象的线程对被保护资源的独自访问
void CMutex::Lock() const
{
	DWORD d = WaitForSingleObject(m_mutex, INFINITE);
}

//释放当前线程拥有的互斥对象,以使其它线程可以拥有互斥对象,对被保护资源进行访问
void CMutex::Unlock() const
{
	::ReleaseMutex(m_mutex);
}

//////////////////////////////////////////////////////////////////////////

//初始化临界资源对象
CriSection::CriSection()
{
	::InitializeCriticalSection(&m_critclSection);
}

//释放临界资源对象
CriSection::~CriSection()
{
	::DeleteCriticalSection(&m_critclSection);
}

//进入临界区,加锁
void CriSection::Lock() const
{
	::EnterCriticalSection((LPCRITICAL_SECTION)&m_critclSection);
}	

//离开临界区,解锁
void CriSection::Unlock() const
{
	::LeaveCriticalSection((LPCRITICAL_SECTION)&m_critclSection);
}

//////////////////////////////////////////////////////////////////////////

//自动加锁
CAutoLock::CAutoLock(const ILock& m) : m_lock(m)
{
	m_lock.Lock();
}

//自动解锁
CAutoLock::~CAutoLock()
{
	m_lock.Unlock();
}

测试代码: 

#include "Lock.h"
#include <iostream>
#include <process.h>
#include <time.h>
using namespace std;


#define ENABLE_MUTEX
#define ENABLE_CRITICAL_SECTION

#if defined (ENABLE_MUTEX)
CMutex g_Lock;//创建一个互斥对象类型锁
#elif defined (ENABLE_CRITICAL_SECTION)
CriSection g_Lock;//创建一个临界区类型锁
#endif


void LockCompare(int &nNum)
{
	CAutoLock lock1(g_Lock);
	nNum++;
}


//线程函数
unsigned int __stdcall StartThread(void *pParam)
{
	char *pMsg = (char *)pParam;
	if (!pMsg)
	{
		return (unsigned int)1;
	}

	CAutoLock lock2(g_Lock);
	cout << pMsg << endl;

	clock_t tStart = clock();
	int nNum = 0;
	for (int i=0; i<100000; i++)
	{
		LockCompare(nNum);//对nNum反复加锁
	}
	clock_t tEnd = clock();

#if defined (ENABLE_MUTEX)
	cout << "The lock type is mutex, time = " << (tEnd - tStart) << " ms." << endl;
#elif defined (ENABLE_CRITICAL_SECTION)
	cout << "The lock type is critical section, time = "<<(tEnd - tStart) << " ms." <<endl;
#endif

	return (unsigned int)0;
}

int main(int argc, char* argv[])
{
	unsigned int uThreadId1, uThreadId2;

	char *pszMsg1 = "1st print thread.";
	char *pszMsg2 = "2nd print thread.";

	//创建两个工作线程,分别打印不同的消息
	HANDLE hThread1 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)pszMsg1, 0, &uThreadId1);
	HANDLE hThread2 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)pszMsg2, 0, &uThreadId2);

	//等待线程结束
	DWORD dwRet = WaitForSingleObject(hThread1,INFINITE);
	if ( dwRet == WAIT_TIMEOUT )
	{
		TerminateThread(hThread1, 0);
	}
	dwRet = WaitForSingleObject(hThread2,INFINITE);
	if ( dwRet == WAIT_TIMEOUT )
	{
		TerminateThread(hThread2, 0);
	}

	//关闭线程句柄,释放资源
	::CloseHandle(hThread1);
	::CloseHandle(hThread2);

	system("pause");
	return 0;
}

将测试代码中的宏 #define ENABLE_MUTEX 注释掉,禁掉互斥锁,启用临界区锁。对比测试,可以看出关键段的效率比互斥量要高!

有以下几点需要注意:

1、关键段与互斥量,两者都因为有“线程所有权”,所以只能用于线程的互斥,不可以用于线程的同步。

2、在同一个进程的多线程同步锁,宜用关键段锁,它的效率比互斥量要高!

 

#include <winsock2.h> #include <MSTcpIP.h> #pragma comment(lib,"ws2_32.lib") #include "Buffer.h" #include "CpuUsage.h" #include <process.h> #include <afxtempl.h> //////////////////////////////////////////////////////////////////// #define NC_CLIENT_CONNECT 0x0001 #define NC_CLIENT_DISCONNECT 0x0002 #define NC_TRANSMIT 0x0003 #define NC_RECEIVE 0x0004 #define NC_RECEIVE_COMPLETE 0x0005 // 完整接收 class CLock { public: CLock(CRITICAL_SECTION& cs, const CString& strFunc) { m_strFunc = strFunc; m_pcs = &cs; Lock(); } ~CLock() { Unlock(); } void Unlock() { LeaveCriticalSection(m_pcs); TRACE(_T("LC %d %s\n") , GetCurrentThreadId() , m_strFunc); } void Lock() { TRACE(_T("EC %d %s\n") , GetCurrentThreadId(), m_strFunc); EnterCriticalSection(m_pcs); } protected: CRITICAL_SECTION* m_pcs; CString m_strFunc; }; enum IOType { IOInitialize, IORead, IOWrite, IOIdle }; class OVERLAPPEDPLUS { public: OVERLAPPED m_ol; IOType m_ioType; OVERLAPPEDPLUS(IOType ioType) { ZeroMemory(this, sizeof(OVERLAPPEDPLUS)); m_ioType = ioType; } }; //lang2.1_3 struct ClientContext //简单分析ClientContext结构体然后回到 SendSelectCommand { SOCKET m_Socket; //套接字 // Store buffers CBuffer m_WriteBuffer; CBuffer m_CompressionBuffer; // 接收到的压缩的数据 CBuffer m_DeCompressionBuffer; // 解压后的数据 CBuffer m_ResendWriteBuffer; // 上次发送的数据包,接收失败时重发时用 int m_Dialog[2]; // 放对话框列表用,第一个int是类型,第二个是CDialog的地址 int m_nTransferProgress; // Input Elements for Winsock WSABUF m_wsaInBuffer; BYTE m_byInBuffer[8192]; // Output elements for Winsock WSABUF m_wsaOutBuffer; HANDLE m_hWriteComplete; // Message counts... purely for example purposes LONG m_nMsgIn; LONG m_nMsgOut; BOOL m_bIsMainSocket; // 是不是主socket ClientContext* m_pWriteContext; ClientContext* m_pReadContext; }; template<> inline UINT AFXAPI HashKey(CString & strGuid) { return HashKey( (LPCTSTR) strGuid); } #include "Mapper.h" typedef void (CALLBACK* NOTIFYPROC)(LPVOID, ClientContext*, UINT nCode); typedef CList<ClientContext*, ClientContext* > ContextList; class CMainFrame; class CIOCPServer { public: void DisconnectAll(); CIOCPServer(); virtual ~CIOCPServer(); NOTIFYPROC m_pNotifyProc; CMainFrame* m_pFrame; bool Initialize(NOTIFYPROC pNotifyProc, CMainFrame* pFrame, int nMaxConnections, int nPort); static unsigned __stdcall ListenThreadProc(LPVOID lpVoid); static unsigned __stdcall ThreadPoolFunc(LPVOID WorkContext); static CRITICAL_SECTION m_cs; void Send(ClientContext* pContext, LPBYTE lpData, UINT nSize); void PostRecv(ClientContext* pContext); bool IsRunning(); void Shutdown(); void ResetConnection(ClientContext* pContext); LONG m_nCurrentThreads; LONG m_nBusyThreads; UINT m_nSendKbps; // 发送即时速度 UINT m_nRecvKbps; // 接受即时速度 UINT m_nMaxConnections; // 最大连接数 protected: void InitializeClientRead(ClientContext* pContext); BOOL AssociateSocketWithCompletionPort(SOCKET device, HANDLE hCompletionPort, DWORD dwCompletionKey); void RemoveStaleClient(ClientContext* pContext, BOOL bGraceful); void MoveToFreePool(ClientContext *pContext); ClientContext* AllocateContext(); LONG m_nWorkerCnt; bool m_bInit; bool m_bDisconnectAll; BYTE m_bPacketFlag[5]; void CloseCompletionPort(); void OnAccept(); bool InitializeIOCP(void); void Stop(); ContextList m_listContexts; ContextList m_listFreePool; WSAEVENT m_hEvent; SOCKET m_socListen; HANDLE m_hKillEvent; HANDLE m_hThread; HANDLE m_hCompletionPort; bool m_bTimeToKill; CCpuUsage m_cpu; LONG m_nKeepLiveTime; // 心跳超时 // Thread Pool Tunables LONG m_nThreadPoolMin; LONG m_nThreadPoolMax; LONG m_nCPULoThreshold; LONG m_nCPUHiThreshold; CString GetHostName(SOCKET socket); void CreateStream(ClientContext* pContext); BEGIN_IO_MSG_MAP() IO_MESSAGE_HANDLER(IORead, OnClientReading) IO_MESSAGE_HANDLER(IOWrite, OnClientWriting) IO_MESSAGE_HANDLER(IOInitialize, OnClientInitializing) END_IO_MSG_MAP() bool OnClientInitializing (ClientContext* pContext, DWORD dwSize = 0); bool OnClientReading (ClientContext* pContext, DWORD dwSize = 0); bool OnClientWriting (ClientContext* pContext, DWORD dwSize = 0); };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值